brw1

Dependencies:   mbed

Files at this revision

API Documentation at this revision

Comitter:
reiniermarcel
Date:
Mon Nov 30 11:13:18 2015 +0000
Commit message:
ok

Changed in this revision

RA8875/Arial12x12.h Show annotated file Show diff for this revision Revisions of this file
RA8875/Bitmap.h Show annotated file Show diff for this revision Revisions of this file
RA8875/DisplayDefs.h Show annotated file Show diff for this revision Revisions of this file
RA8875/GraphicsDisplay.cpp Show annotated file Show diff for this revision Revisions of this file
RA8875/GraphicsDisplay.h Show annotated file Show diff for this revision Revisions of this file
RA8875/RA8875.cpp Show annotated file Show diff for this revision Revisions of this file
RA8875/RA8875.h Show annotated file Show diff for this revision Revisions of this file
RA8875/RA8875_Regs.h Show annotated file Show diff for this revision Revisions of this file
RA8875/RA8875_Touch.cpp Show annotated file Show diff for this revision Revisions of this file
RA8875/Small_6.h Show annotated file Show diff for this revision Revisions of this file
RA8875/TextDisplay.cpp Show annotated file Show diff for this revision Revisions of this file
RA8875/TextDisplay.h Show annotated file Show diff for this revision Revisions of this file
RA8875/WebColors.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/RA8875/Arial12x12.h	Mon Nov 30 11:13:18 2015 +0000
@@ -0,0 +1,111 @@
+#ifndef ARIAL12X12_H
+#define ARIAL12X12_H
+
+//GLCD FontName : Arial12x12
+//GLCD FontSize : 12 x 12
+
+/** Arial Font with 12*12 matrix to use with SPI_TFT lib */
+//__align(2)
+
+const unsigned char Arial12x12[] = {
+    25,12,12,2,                   // Bytes/char, horz, vert, byte/vert
+    //width, pixel stream ....
+    0x07, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char
+    0x02, 0X00, 0X00, 0x7F, 0x01, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char !
+    0x03, 0x07, 0X00, 0X00, 0X00, 0x07, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char "
+    0x07, 0x24, 0X00, 0xA4, 0x01, 0x7C, 0X00, 0xA7, 0x01, 0x7C, 0X00, 0x27, 0X00, 0x24, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char #
+    0x06, 0X00, 0X00, 0xCE, 0X00, 0x11, 0x01, 0xFF, 0x03, 0x11, 0x01, 0xE2, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char $
+    0x0A, 0X00, 0X00, 0x0E, 0X00, 0x11, 0X00, 0x11, 0x01, 0xCE, 0X00, 0x38, 0X00, 0xE6, 0X00, 0x11, 0x01, 0x10, 0x01, 0xE0, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char %
+    0x08, 0X00, 0X00, 0xE0, 0X00, 0x1E, 0x01, 0x11, 0x01, 0x29, 0x01, 0xC6, 0X00, 0xA0, 0X00, 0X00, 0x01, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char &
+    0x02, 0X00, 0X00, 0x07, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char '
+    0x04, 0X00, 0X00, 0xF8, 0X00, 0x06, 0x03, 0x01, 0x04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char (
+    0x03, 0x01, 0x04, 0x06, 0x03, 0xF8, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char )
+    0x05, 0x02, 0X00, 0x0A, 0X00, 0x07, 0X00, 0x0A, 0X00, 0x02, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char *
+    0x06, 0X00, 0X00, 0x10, 0X00, 0x10, 0X00, 0x7C, 0X00, 0x10, 0X00, 0x10, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char +
+    0x02, 0X00, 0X00, 0X00, 0x07, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char ,
+    0x03, 0x20, 0X00, 0x20, 0X00, 0x20, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char -
+    0x02, 0X00, 0X00, 0X00, 0x01, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char .
+    0x03, 0x80, 0x01, 0x7C, 0X00, 0x03, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char /
+    0x06, 0X00, 0X00, 0xFE, 0X00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0xFE, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char 0
+    0x06, 0X00, 0X00, 0x04, 0X00, 0x02, 0X00, 0xFF, 0x01, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char 1
+    0x06, 0X00, 0X00, 0x02, 0x01, 0x81, 0x01, 0x41, 0x01, 0x31, 0x01, 0x0E, 0x01, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char 2
+    0x06, 0X00, 0X00, 0x82, 0X00, 0x01, 0x01, 0x11, 0x01, 0x11, 0x01, 0xEE, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char 3
+    0x06, 0X00, 0X00, 0x60, 0X00, 0x58, 0X00, 0x46, 0X00, 0xFF, 0x01, 0x40, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char 4
+    0x06, 0X00, 0X00, 0x9C, 0X00, 0x0B, 0x01, 0x09, 0x01, 0x09, 0x01, 0xF1, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char 5
+    0x06, 0X00, 0X00, 0xFE, 0X00, 0x11, 0x01, 0x09, 0x01, 0x09, 0x01, 0xF2, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char 6
+    0x06, 0X00, 0X00, 0x01, 0X00, 0xC1, 0x01, 0x39, 0X00, 0x07, 0X00, 0x01, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char 7
+    0x06, 0X00, 0X00, 0xEE, 0X00, 0x11, 0x01, 0x11, 0x01, 0x11, 0x01, 0xEE, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char 8
+    0x06, 0X00, 0X00, 0x9E, 0X00, 0x21, 0x01, 0x21, 0x01, 0x11, 0x01, 0xFE, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char 9
+    0x02, 0X00, 0X00, 0x04, 0x01, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char :
+    0x02, 0X00, 0X00, 0x40, 0x07, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char ;
+    0x06, 0X00, 0X00, 0x10, 0X00, 0x28, 0X00, 0x28, 0X00, 0x44, 0X00, 0x44, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char <
+    0x06, 0x48, 0X00, 0x48, 0X00, 0x48, 0X00, 0x48, 0X00, 0x48, 0X00, 0x48, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char =
+    0x06, 0X00, 0X00, 0x44, 0X00, 0x44, 0X00, 0x28, 0X00, 0x28, 0X00, 0x10, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char >
+    0x06, 0X00, 0X00, 0x06, 0X00, 0x01, 0X00, 0x61, 0x01, 0x11, 0X00, 0x0E, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char ?
+    0x0C, 0X00, 0X00, 0xF0, 0x01, 0x0C, 0x02, 0xE2, 0x04, 0x12, 0x09, 0x09, 0x09, 0x09, 0x09, 0xF1, 0x09, 0x19, 0x09, 0x02, 0x05, 0x86, 0x04, 0x78, 0x02,  // Code for char @
+    0x07, 0x80, 0x01, 0x70, 0X00, 0x2E, 0X00, 0x21, 0X00, 0x2E, 0X00, 0x70, 0X00, 0x80, 0x01, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char A
+    0x07, 0X00, 0X00, 0xFF, 0x01, 0x11, 0x01, 0x11, 0x01, 0x11, 0x01, 0x11, 0x01, 0xFE, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char B
+    0x08, 0X00, 0X00, 0x7C, 0X00, 0x82, 0X00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x82, 0X00, 0x44, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char C
+    0x08, 0X00, 0X00, 0xFF, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x82, 0X00, 0x7C, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char D
+    0x07, 0X00, 0X00, 0xFF, 0x01, 0x11, 0x01, 0x11, 0x01, 0x11, 0x01, 0x11, 0x01, 0x11, 0x01, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char E
+    0x06, 0X00, 0X00, 0xFF, 0x01, 0x11, 0X00, 0x11, 0X00, 0x11, 0X00, 0x01, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char F
+    0x08, 0X00, 0X00, 0x7C, 0X00, 0x82, 0X00, 0x01, 0x01, 0x01, 0x01, 0x11, 0x01, 0x92, 0X00, 0x74, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char G
+    0x08, 0X00, 0X00, 0xFF, 0x01, 0x10, 0X00, 0x10, 0X00, 0x10, 0X00, 0x10, 0X00, 0x10, 0X00, 0xFF, 0x01, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char H
+    0x03, 0X00, 0X00, 0xFF, 0x01, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char I
+    0x05, 0xC0, 0X00, 0X00, 0x01, 0X00, 0x01, 0X00, 0x01, 0xFF, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char J
+    0x08, 0X00, 0X00, 0xFF, 0x01, 0x20, 0X00, 0x10, 0X00, 0x28, 0X00, 0x44, 0X00, 0x82, 0X00, 0x01, 0x01, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char K
+    0x07, 0X00, 0X00, 0xFF, 0x01, 0X00, 0x01, 0X00, 0x01, 0X00, 0x01, 0X00, 0x01, 0X00, 0x01, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char L
+    0x08, 0X00, 0X00, 0xFF, 0x01, 0x06, 0X00, 0x78, 0X00, 0x80, 0x01, 0x78, 0X00, 0x06, 0X00, 0xFF, 0x01, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char M
+    0x08, 0X00, 0X00, 0xFF, 0x01, 0x02, 0X00, 0x0C, 0X00, 0x10, 0X00, 0x60, 0X00, 0x80, 0X00, 0xFF, 0x01, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char N
+    0x08, 0X00, 0X00, 0x7C, 0X00, 0x82, 0X00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x82, 0X00, 0x7C, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char O
+    0x07, 0X00, 0X00, 0xFF, 0x01, 0x11, 0X00, 0x11, 0X00, 0x11, 0X00, 0x11, 0X00, 0x0E, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char P
+    0x08, 0X00, 0X00, 0x7C, 0X00, 0x82, 0X00, 0x01, 0x01, 0x41, 0x01, 0x41, 0x01, 0x82, 0X00, 0x7C, 0x01, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char Q
+    0x08, 0X00, 0X00, 0xFF, 0x01, 0x11, 0X00, 0x11, 0X00, 0x11, 0X00, 0x31, 0X00, 0xD1, 0X00, 0x0E, 0x01, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char R
+    0x07, 0X00, 0X00, 0xCE, 0X00, 0x11, 0x01, 0x11, 0x01, 0x11, 0x01, 0x11, 0x01, 0xE6, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char S
+    0x07, 0x01, 0X00, 0x01, 0X00, 0x01, 0X00, 0xFF, 0x01, 0x01, 0X00, 0x01, 0X00, 0x01, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char T
+    0x08, 0X00, 0X00, 0x7F, 0X00, 0x80, 0X00, 0X00, 0x01, 0X00, 0x01, 0X00, 0x01, 0x80, 0X00, 0x7F, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char U
+    0x07, 0x03, 0X00, 0x1C, 0X00, 0x60, 0X00, 0x80, 0x01, 0x60, 0X00, 0x1C, 0X00, 0x03, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char V
+    0x0B, 0x07, 0X00, 0x78, 0X00, 0x80, 0x01, 0x70, 0X00, 0x0E, 0X00, 0x01, 0X00, 0x0E, 0X00, 0x70, 0X00, 0x80, 0x01, 0x7C, 0X00, 0x03, 0X00, 0X00, 0X00,  // Code for char W
+    0x07, 0x01, 0x01, 0xC6, 0X00, 0x28, 0X00, 0x10, 0X00, 0x28, 0X00, 0xC6, 0X00, 0x01, 0x01, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char X
+    0x07, 0x01, 0X00, 0x06, 0X00, 0x08, 0X00, 0xF0, 0x01, 0x08, 0X00, 0x06, 0X00, 0x01, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char Y
+    0x07, 0X00, 0x01, 0x81, 0x01, 0x61, 0x01, 0x11, 0x01, 0x0D, 0x01, 0x03, 0x01, 0x01, 0x01, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char Z
+    0x03, 0X00, 0X00, 0xFF, 0x07, 0x01, 0x04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char [
+    0x03, 0x03, 0X00, 0x7C, 0X00, 0x80, 0x01, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char BackSlash
+    0x02, 0x01, 0x04, 0xFF, 0x07, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char ]
+    0x05, 0x18, 0X00, 0x06, 0X00, 0x01, 0X00, 0x06, 0X00, 0x18, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char ^
+    0x07, 0X00, 0x04, 0X00, 0x04, 0X00, 0x04, 0X00, 0x04, 0X00, 0x04, 0X00, 0x04, 0X00, 0x04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char _
+    0x03, 0X00, 0X00, 0x01, 0X00, 0x02, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char `
+    0x06, 0X00, 0X00, 0xC8, 0X00, 0x24, 0x01, 0x24, 0x01, 0xA4, 0X00, 0xF8, 0x01, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char a
+    0x06, 0X00, 0X00, 0xFF, 0x01, 0x88, 0X00, 0x04, 0x01, 0x04, 0x01, 0xF8, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char b
+    0x05, 0X00, 0X00, 0xF8, 0X00, 0x04, 0x01, 0x04, 0x01, 0x88, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char c
+    0x06, 0X00, 0X00, 0xF8, 0X00, 0x04, 0x01, 0x04, 0x01, 0x08, 0x01, 0xFF, 0x01, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char d
+    0x06, 0X00, 0X00, 0xF8, 0X00, 0x24, 0x01, 0x24, 0x01, 0x24, 0x01, 0xB8, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char e
+    0x04, 0x04, 0X00, 0xFE, 0x01, 0x05, 0X00, 0x01, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char f
+    0x06, 0X00, 0X00, 0xF8, 0x04, 0x04, 0x05, 0x04, 0x05, 0x88, 0x04, 0xFC, 0x03, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char g
+    0x06, 0X00, 0X00, 0xFF, 0x01, 0x08, 0X00, 0x04, 0X00, 0x04, 0X00, 0xF8, 0x01, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char h
+    0x02, 0X00, 0X00, 0xFD, 0x01, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char i
+    0x02, 0X00, 0x04, 0xFD, 0x03, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char j
+    0x06, 0X00, 0X00, 0xFF, 0x01, 0x20, 0X00, 0x30, 0X00, 0xC8, 0X00, 0x04, 0x01, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char k
+    0x02, 0X00, 0X00, 0xFF, 0x01, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char l
+    0x0A, 0X00, 0X00, 0xFC, 0x01, 0x08, 0X00, 0x04, 0X00, 0x04, 0X00, 0xF8, 0x01, 0x08, 0X00, 0x04, 0X00, 0x04, 0X00, 0xF8, 0x01, 0X00, 0X00, 0X00, 0X00,  // Code for char m
+    0x06, 0X00, 0X00, 0xFC, 0x01, 0x08, 0X00, 0x04, 0X00, 0x04, 0X00, 0xF8, 0x01, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char n
+    0x06, 0X00, 0X00, 0xF8, 0X00, 0x04, 0x01, 0x04, 0x01, 0x04, 0x01, 0xF8, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char o
+    0x06, 0X00, 0X00, 0xFC, 0x07, 0x88, 0X00, 0x04, 0x01, 0x04, 0x01, 0xF8, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char p
+    0x06, 0X00, 0X00, 0xF8, 0X00, 0x04, 0x01, 0x04, 0x01, 0x88, 0X00, 0xFC, 0x07, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char q
+    0x04, 0X00, 0X00, 0xFC, 0x01, 0x08, 0X00, 0x04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char r
+    0x06, 0X00, 0X00, 0x98, 0X00, 0x24, 0x01, 0x24, 0x01, 0x24, 0x01, 0xC8, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char s
+    0x03, 0x04, 0X00, 0xFF, 0x01, 0x04, 0x01, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char t
+    0x06, 0X00, 0X00, 0xFC, 0X00, 0X00, 0x01, 0X00, 0x01, 0X00, 0x01, 0xFC, 0x01, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char u
+    0x05, 0x0C, 0X00, 0x70, 0X00, 0x80, 0x01, 0x70, 0X00, 0x0C, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char v
+    0x09, 0x0C, 0X00, 0x70, 0X00, 0x80, 0x01, 0x70, 0X00, 0x0C, 0X00, 0x70, 0X00, 0x80, 0x01, 0x70, 0X00, 0x0C, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char w
+    0x05, 0x04, 0x01, 0xD8, 0X00, 0x20, 0X00, 0xD8, 0X00, 0x04, 0x01, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char x
+    0x05, 0x0C, 0X00, 0x70, 0x04, 0x80, 0x03, 0x70, 0X00, 0x0C, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char y
+    0x05, 0x04, 0x01, 0xC4, 0x01, 0x24, 0x01, 0x1C, 0x01, 0x04, 0x01, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char z
+    0x03, 0x20, 0X00, 0xDE, 0x03, 0x01, 0x04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char {
+    0x02, 0X00, 0X00, 0xFF, 0x07, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char |
+    0x04, 0X00, 0X00, 0x01, 0x04, 0xDE, 0x03, 0x20, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char }
+    0x07, 0X00, 0X00, 0x20, 0X00, 0x10, 0X00, 0x10, 0X00, 0x20, 0X00, 0x20, 0X00, 0x10, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00,  // Code for char ~
+    0x08, 0X00, 0X00, 0xFE, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0xFE, 0x01, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00   // Code for char <del>
+};
+
+#endif // ARIAL12X12_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/RA8875/Bitmap.h	Mon Nov 30 11:13:18 2015 +0000
@@ -0,0 +1,102 @@
+//
+// Windows BMP file definitions.
+//
+// Adapted from code written by Michael Sweet from Paul Bourke's
+// web site: http://paulbourke.net/dataformats/bmp/
+//
+
+#ifndef _BITMAP_H_
+#define _BITMAP_H_
+
+#include <mbed.h>
+
+// BITMAPFILEHEADER
+// BITMAPINFOHEADER
+// Optional Palette
+// Raw Data
+
+//
+// Bitmap file data structures
+//
+// must align to 2-byte boundaries so it doesn't alter the memory image when 
+// bytes are read from the file system into this footprint.
+#pragma push
+#pragma pack(2)
+
+typedef struct                    /**** BMP file header structure ****/
+    {
+    uint16_t    bfType;           /* Magic number for file */
+    uint32_t    bfSize;           /* Size of file */
+    uint16_t    bfReserved1;      /* Reserved */
+    uint16_t    bfReserved2;      /* ... */
+    uint32_t    bfOffBits;        /* Offset to bitmap data */
+    } BITMAPFILEHEADER;
+
+typedef struct                    /**** BMP file info structure ****/
+    {
+    uint32_t    biSize;           /* Size of info header */
+    uint32_t    biWidth;          /* Width of image */
+    uint32_t    biHeight;         /* Height of image */
+    uint16_t    biPlanes;         /* Number of color planes */
+    uint16_t    biBitCount;       /* Number of bits per pixel */
+    uint32_t    biCompression;    /* Type of compression to use */
+    uint32_t    biSizeImage;      /* Size of image data */
+    int32_t     biXPelsPerMeter;  /* X pixels per meter */
+    int32_t     biYPelsPerMeter;  /* Y pixels per meter */
+    uint32_t    biClrUsed;        /* Number of colors used */
+    uint32_t    biClrImportant;   /* Number of important colors */
+    } BITMAPINFOHEADER;
+#pragma pop
+
+#define BF_TYPE 0x4D42            /* "MB" */
+
+/*
+ * Constants for the biCompression field...
+ */
+
+#  define BI_RGB       0             /* No compression - straight BGR data */
+#  define BI_RLE8      1             /* 8-bit run-length compression */
+#  define BI_RLE4      2             /* 4-bit run-length compression */
+#  define BI_BITFIELDS 3             /* RGB bitmap with RGB masks */
+
+typedef struct                       /**** Colormap entry structure ****/
+    {
+    uint8_t  rgbBlue;          /* Blue value */
+    uint8_t  rgbGreen;         /* Green value */
+    uint8_t  rgbRed;           /* Red value */
+    uint8_t  rgbReserved;      /* Reserved */
+    } RGBQUAD;
+
+//typedef struct                       /**** Bitmap information structure ****/
+//    {
+//    BITMAPINFOHEADER bmiHeader;      /* Image header */
+//    RGBQUAD          bmiColors[256]; /* Image colormap */
+//    } BITMAPINFO;
+
+
+#pragma push
+#pragma pack(2)
+
+typedef struct                  /**** ICO file header structure ****/
+    {
+    uint16_t    Reserved_zero;  // Always zero
+    uint16_t    icType;         // 1 for .ico, 2 for .cur
+    uint16_t    icImageCount;   // number of images in the file    
+    } ICOFILEHEADER;
+    
+typedef struct                  /**** ICO file Directory Entry structure (1 or more) ****/
+    {
+    uint8_t     biWidth;          /* Width of image */
+    uint8_t     biHeight;         /* Height of image */
+    uint8_t     biClrUsed;        /* Number of colors used */
+    uint8_t     Reserved_zero;
+    uint16_t    biPlanes;         /* Number of color planes (ICO should be 0 or 1, CUR horz hotspot */
+    uint16_t    biBitCount;       /* Number of bits per pixel (ICO bits per pixel, CUR vert hotspot */
+    uint32_t    biSizeImage;      /* Size of image data */
+    uint32_t    bfOffBits;        /* Offset into file for the bitmap data */
+    } ICODIRENTRY;
+#pragma pop
+
+#define IC_TYPE 0x0001            /* 1 = ICO (icon), 2 = CUR (cursor) */
+
+#endif // _BITMAP_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/RA8875/DisplayDefs.h	Mon Nov 30 11:13:18 2015 +0000
@@ -0,0 +1,74 @@
+#ifndef DISPLAYDEFS_H
+#define DISPLAYDEFS_H
+
+#define RGB(r,g,b) ( ((r<<8)&0xF800) | ((g<<3)&0x07E0) | (b>>3) )
+
+typedef uint16_t color_t;
+
+/// return values from functions. Use this number, or use the 
+/// lookup function to get a text string. @see GetErrorMessage.
+///
+typedef enum
+{
+    noerror,                ///< no errors, command completed successfully
+    bad_parameter,          ///< one or more parameters are invalid
+    file_not_found,         ///< specified file could not be found
+    not_bmp_format,         ///< file is not a .bmp file
+    not_ico_format,         ///< file is not a .ico file
+    not_supported_format,   ///< file format is not yet supported
+    image_too_big,          ///< image is too large for the screen
+    not_enough_ram,         ///< could not allocate ram for scanline
+    LastErrCode,            // Private marker.
+} RetCode_t;
+
+/// type that manages locations, which is typically an x or y pixel location,
+/// which can range from -N to +N (even if the screen is 0 to +n). @see textloc_t.
+typedef int16_t loc_t;
+
+/// type that manages text locations, which are row or column values in
+/// units of character, not pixel. @see loc_t.
+typedef uint16_t textloc_t;
+
+/// type that manages dimensions of width or height, which range from 0 to N.
+typedef uint16_t dim_t;
+
+/// type that manages x,y pairs
+typedef struct
+{
+    loc_t x;             ///< x value in the point
+    loc_t y;             ///< y value in the point
+} point_t;
+
+/// type that manages rectangles, which are pairs of points. It is recommended
+/// that p1 contains the top-left point and p2 contains the bottom-right point,
+/// even though eventually this should not matter.
+typedef struct
+{
+    point_t p1;         ///< p1 defines one point on the rectangle
+    point_t p2;         ///< p2 defines the opposite point on the rectangle
+} rect_t;
+
+typedef struct
+{
+    int32_t An, Bn, Cn, Dn, En, Fn, Divider;
+} tpMatrix_t;
+
+/// color type definition to let the compiler help keep us honest.
+/// 
+/// colors can be defined with the RGB(r,g,b) macro, and there
+/// are a number of predefined colors:
+/// - Black,    Blue,       Green,       Cyan,
+/// - Red,      Magenta,    Brown,       Gray,
+/// - Charcoal, BrightBlue, BrightGreen, BrightCyan,
+/// - Orange,   Pink,       Yellow,      White
+///
+typedef uint16_t color_t;   
+
+/// background fill info for drawing Text, Rectangles, RoundedRectanges, Circles, Ellipses and Triangles.
+typedef enum
+{
+    NOFILL,     ///< do not fill the object with the background color
+    FILL        ///< fill the object space with the background color
+} fill_t;
+
+#endif // DISPLAYDEFS_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/RA8875/GraphicsDisplay.cpp	Mon Nov 30 11:13:18 2015 +0000
@@ -0,0 +1,563 @@
+/* mbed GraphicsDisplay Display Library Base Class
+ * Copyright (c) 2007-2009 sford
+ * Released under the MIT License: http://mbed.org/license/mit
+ *
+ * Derivative work by D.Smart 2014
+ */
+
+#include "GraphicsDisplay.h"
+#include "Bitmap.h"
+#include "string.h"
+
+//#define DEBUG "GD"
+// ...
+// INFO("Stuff to show %d", var); // new-line is automatically appended
+//
+#if (defined(DEBUG) && !defined(TARGET_LPC11U24))
+#define INFO(x, ...) std::printf("[INF %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
+#define WARN(x, ...) std::printf("[WRN %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
+#define ERR(x, ...)  std::printf("[ERR %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
+static void HexDump(char * title, uint8_t * p, int count)
+{
+    int i;
+    char buf[100] = "0000: ";
+    
+    if (*title)
+        INFO("%s", title);
+    for (i=0; i<count; ) {
+        sprintf(buf + strlen(buf), "%02X ", *(p+i));
+        if ((++i & 0x0F) == 0x00) {
+            INFO("%s", buf);
+            if (i < count)
+                sprintf(buf, "%04X: ", i);
+            else
+                buf[0] = '\0';
+        }
+    }
+    if (strlen(buf))
+        INFO("%s", buf);
+}
+#else
+#define INFO(x, ...)
+#define WARN(x, ...)
+#define ERR(x, ...)
+#define HexDump(a, b, c)
+#endif
+
+#ifdef LOCALFONT
+const unsigned char FONT8x8[97][8] = {
+    0x08, 0x08, 0x08, 0X00, 0X00, 0X00, 0X00, 0X00, // columns, rows, num_bytes_per_char
+    0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, // space 0x20
+    0x30, 0x78, 0x78, 0x30, 0x30, 0X00, 0x30, 0X00, // !
+    0x6C, 0x6C, 0x6C, 0X00, 0X00, 0X00, 0X00, 0X00, // "
+    0x6C, 0x6C, 0xFE, 0x6C, 0xFE, 0x6C, 0x6C, 0X00, // #
+    0x18, 0x3E, 0x60, 0x3C, 0x06, 0x7C, 0x18, 0X00, // $
+    0X00, 0x63, 0x66, 0x0C, 0x18, 0x33, 0x63, 0X00, // %
+    0x1C, 0x36, 0x1C, 0x3B, 0x6E, 0x66, 0x3B, 0X00, // &
+    0x30, 0x30, 0x60, 0X00, 0X00, 0X00, 0X00, 0X00, // '
+    0x0C, 0x18, 0x30, 0x30, 0x30, 0x18, 0x0C, 0X00, // (
+    0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x18, 0x30, 0X00, // )
+    0X00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0X00, 0X00, // *
+    0X00, 0x30, 0x30, 0xFC, 0x30, 0x30, 0X00, 0X00, // +
+    0X00, 0X00, 0X00, 0X00, 0X00, 0x18, 0x18, 0x30, // ,
+    0X00, 0X00, 0X00, 0x7E, 0X00, 0X00, 0X00, 0X00, // -
+    0X00, 0X00, 0X00, 0X00, 0X00, 0x18, 0x18, 0X00, // .
+    0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x40, 0X00, // / (forward slash)
+    0x3E, 0x63, 0x63, 0x6B, 0x63, 0x63, 0x3E, 0X00, // 0 0x30
+    0x18, 0x38, 0x58, 0x18, 0x18, 0x18, 0x7E, 0X00, // 1
+    0x3C, 0x66, 0x06, 0x1C, 0x30, 0x66, 0x7E, 0X00, // 2
+    0x3C, 0x66, 0x06, 0x1C, 0x06, 0x66, 0x3C, 0X00, // 3
+    0x0E, 0x1E, 0x36, 0x66, 0x7F, 0x06, 0x0F, 0X00, // 4
+    0x7E, 0x60, 0x7C, 0x06, 0x06, 0x66, 0x3C, 0X00, // 5
+    0x1C, 0x30, 0x60, 0x7C, 0x66, 0x66, 0x3C, 0X00, // 6
+    0x7E, 0x66, 0x06, 0x0C, 0x18, 0x18, 0x18, 0X00, // 7
+    0x3C, 0x66, 0x66, 0x3C, 0x66, 0x66, 0x3C, 0X00, // 8
+    0x3C, 0x66, 0x66, 0x3E, 0x06, 0x0C, 0x38, 0X00, // 9
+    0X00, 0x18, 0x18, 0X00, 0X00, 0x18, 0x18, 0X00, // :
+    0X00, 0x18, 0x18, 0X00, 0X00, 0x18, 0x18, 0x30, // ;
+    0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C, 0X00, // <
+    0X00, 0X00, 0x7E, 0X00, 0X00, 0x7E, 0X00, 0X00, // =
+    0x30, 0x18, 0x0C, 0x06, 0x0C, 0x18, 0x30, 0X00, // >
+    0x3C, 0x66, 0x06, 0x0C, 0x18, 0X00, 0x18, 0X00, // ?
+    0x3E, 0x63, 0x6F, 0x69, 0x6F, 0x60, 0x3E, 0X00, // @ 0x40
+    0x18, 0x3C, 0x66, 0x66, 0x7E, 0x66, 0x66, 0X00, // A
+    0x7E, 0x33, 0x33, 0x3E, 0x33, 0x33, 0x7E, 0X00, // B
+    0x1E, 0x33, 0x60, 0x60, 0x60, 0x33, 0x1E, 0X00, // C
+    0x7C, 0x36, 0x33, 0x33, 0x33, 0x36, 0x7C, 0X00, // D
+    0x7F, 0x31, 0x34, 0x3C, 0x34, 0x31, 0x7F, 0X00, // E
+    0x7F, 0x31, 0x34, 0x3C, 0x34, 0x30, 0x78, 0X00, // F
+    0x1E, 0x33, 0x60, 0x60, 0x67, 0x33, 0x1F, 0X00, // G
+    0x66, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0X00, // H
+    0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0X00, // I
+    0x0F, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3C, 0X00, // J
+    0x73, 0x33, 0x36, 0x3C, 0x36, 0x33, 0x73, 0X00, // K
+    0x78, 0x30, 0x30, 0x30, 0x31, 0x33, 0x7F, 0X00, // L
+    0x63, 0x77, 0x7F, 0x7F, 0x6B, 0x63, 0x63, 0X00, // M
+    0x63, 0x73, 0x7B, 0x6F, 0x67, 0x63, 0x63, 0X00, // N
+    0x3E, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3E, 0X00, // O
+    0x7E, 0x33, 0x33, 0x3E, 0x30, 0x30, 0x78, 0X00, // P 0x50
+    0x3C, 0x66, 0x66, 0x66, 0x6E, 0x3C, 0x0E, 0X00, // Q
+    0x7E, 0x33, 0x33, 0x3E, 0x36, 0x33, 0x73, 0X00, // R
+    0x3C, 0x66, 0x30, 0x18, 0x0C, 0x66, 0x3C, 0X00, // S
+    0x7E, 0x5A, 0x18, 0x18, 0x18, 0x18, 0x3C, 0X00, // T
+    0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7E, 0X00, // U
+    0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0X00, // V
+    0x63, 0x63, 0x63, 0x6B, 0x7F, 0x77, 0x63, 0X00, // W
+    0x63, 0x63, 0x36, 0x1C, 0x1C, 0x36, 0x63, 0X00, // X
+    0x66, 0x66, 0x66, 0x3C, 0x18, 0x18, 0x3C, 0X00, // Y
+    0x7F, 0x63, 0x46, 0x0C, 0x19, 0x33, 0x7F, 0X00, // Z
+    0x3C, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3C, 0X00, // [
+    0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0X00, // \ (back slash)
+    0x3C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x3C, 0X00, // ]
+    0x08, 0x1C, 0x36, 0x63, 0X00, 0X00, 0X00, 0X00, // ^
+    0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0xFF, // _
+    0x18, 0x18, 0x0C, 0X00, 0X00, 0X00, 0X00, 0X00, // ` 0x60
+    0X00, 0X00, 0x3C, 0x06, 0x3E, 0x66, 0x3B, 0X00, // a
+    0x70, 0x30, 0x3E, 0x33, 0x33, 0x33, 0x6E, 0X00, // b
+    0X00, 0X00, 0x3C, 0x66, 0x60, 0x66, 0x3C, 0X00, // c
+    0x0E, 0x06, 0x3E, 0x66, 0x66, 0x66, 0x3B, 0X00, // d
+    0X00, 0X00, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0X00, // e
+    0x1C, 0x36, 0x30, 0x78, 0x30, 0x30, 0x78, 0X00, // f
+    0X00, 0X00, 0x3B, 0x66, 0x66, 0x3E, 0x06, 0x7C, // g
+    0x70, 0x30, 0x36, 0x3B, 0x33, 0x33, 0x73, 0X00, // h
+    0x18, 0X00, 0x38, 0x18, 0x18, 0x18, 0x3C, 0X00, // i
+    0x06, 0X00, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3C, // j
+    0x70, 0x30, 0x33, 0x36, 0x3C, 0x36, 0x73, 0X00, // k
+    0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0X00, // l
+    0X00, 0X00, 0x66, 0x7F, 0x7F, 0x6B, 0x63, 0X00, // m
+    0X00, 0X00, 0x7C, 0x66, 0x66, 0x66, 0x66, 0X00, // n
+    0X00, 0X00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0X00, // o
+    0X00, 0X00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x78, // p
+    0X00, 0X00, 0x3B, 0x66, 0x66, 0x3E, 0x06, 0x0F, // q
+    0X00, 0X00, 0x6E, 0x3B, 0x33, 0x30, 0x78, 0X00, // r
+    0X00, 0X00, 0x3E, 0x60, 0x3C, 0x06, 0x7C, 0X00, // s
+    0x08, 0x18, 0x3E, 0x18, 0x18, 0x1A, 0x0C, 0X00, // t
+    0X00, 0X00, 0x66, 0x66, 0x66, 0x66, 0x3B, 0X00, // u
+    0X00, 0X00, 0x66, 0x66, 0x66, 0x3C, 0x18, 0X00, // v
+    0X00, 0X00, 0x63, 0x6B, 0x7F, 0x7F, 0x36, 0X00, // w
+    0X00, 0X00, 0x63, 0x36, 0x1C, 0x36, 0x63, 0X00, // x
+    0X00, 0X00, 0x66, 0x66, 0x66, 0x3E, 0x06, 0x7C, // y
+    0X00, 0X00, 0x7E, 0x4C, 0x18, 0x32, 0x7E, 0X00, // z
+    0x0E, 0x18, 0x18, 0x70, 0x18, 0x18, 0x0E, 0X00, // {
+    0x0C, 0x0C, 0x0C, 0X00, 0x0C, 0x0C, 0x0C, 0X00, // |
+    0x70, 0x18, 0x18, 0x0E, 0x18, 0x18, 0x70, 0X00, // }
+    0x3B, 0x6E, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, // ~
+    0x1C, 0x36, 0x36, 0x1C, 0X00, 0X00, 0X00, 0X00  // DEL
+}; 
+#endif // LOCALFONT
+
+char mytolower(char a) {
+    if (a >= 'A' && a <= 'Z')
+        return (a - 'A' + 'a');
+    else
+        return a;
+}
+/// mystrnicmp exists because not all compiler libraries have this function.
+///
+/// Some have strnicmp, others _strnicmp, and others have C++ methods, which
+/// is outside the scope of this C-portable set of functions.
+///
+/// @param l is a pointer to the string on the left
+/// @param r is a pointer to the string on the right
+/// @param n is the number of characters to compare
+/// @returns -1 if l < r
+/// @returns 0 if l == r
+/// @returns +1 if l > r
+///
+int mystrnicmp(const char *l, const char *r, size_t n) {
+    int result = 0;
+
+    if (n != 0) {
+        do {
+            result = mytolower(*l++) - mytolower(*r++);
+        } while ((result == 0) && (*l != '\0') && (--n > 0));
+    }
+    if (result < -1)
+        result = -1;
+    else if (result > 1)
+        result = 1;
+    return result;
+}
+
+
+GraphicsDisplay::GraphicsDisplay(const char *name) 
+    : TextDisplay(name)
+{
+    font = NULL;
+}
+
+RetCode_t GraphicsDisplay::set_font(const unsigned char * _font)
+{
+    font = _font;     // trusting them, but it might be good to put some checks in here...
+    return noerror;
+}
+
+#ifdef LOCALFONT
+int GraphicsDisplay::character(int x, int y, int value)
+{
+    if (value <= 0x1F && value >= 7F)
+        return 0;
+    
+    return blitbit(x, y, FONT8X8[0][0], FONT8X8[0][1], 
+        (char *)&(FONT8x8[value - 0x1F][0]));
+}
+#else
+int GraphicsDisplay::character(int x, int y, int c)
+{
+    unsigned int offset;
+    const unsigned char * charRecord;
+ 
+    if (c <= 0x1F || c >= 0x7F)
+        return 0;
+    offset = font[0];                    // bytes / char
+    charRecord = &font[((c - ' ') * offset) + 4];      // start of char bitmap
+    return fontblit(x, y, font, charRecord);
+}
+#endif
+
+RetCode_t GraphicsDisplay::window(loc_t x, loc_t y, dim_t w, dim_t h)
+{
+    // current pixel location
+    _x = x;
+    _y = y;
+    // window settings
+    _x1 = x;
+    _x2 = x + w - 1;
+    _y1 = y;
+    _y2 = y + h - 1;
+    return noerror;
+}
+
+RetCode_t GraphicsDisplay::WindowMax(void)
+{
+    return window(0,0, width(),height());
+}
+
+RetCode_t GraphicsDisplay::_putp(color_t color)
+{
+    pixel(_x, _y, color);
+    // update pixel location based on window settings
+    _x++;
+    if(_x > _x2) {
+        _x = _x1;
+        _y++;
+        if(_y > _y2) {
+            _y = _y1;
+        }
+    }
+    return noerror;
+}
+
+RetCode_t GraphicsDisplay::fill(int x, int y, int w, int h, color_t color)
+{
+    return fillrect(x,y, x+w, y+h, color);
+}
+
+RetCode_t GraphicsDisplay::cls(uint16_t layers)
+{
+    return fill(0, 0, width(), height(), _background);
+}
+
+RetCode_t GraphicsDisplay::blit(int x, int y, int w, int h, const int * color)
+{
+    window(x, y, w, h);
+    _StartGraphicsStream();
+    for (int i=0; i<w*h; i++) {
+        _putp(color[i]);
+    }
+    _EndGraphicsStream();
+    return WindowMax();
+}
+
+#ifdef LOCALFONT
+int GraphicsDisplay::blitbit(int x, int y, int w, int h, const char * color)
+{
+    _foreground = 0xFFFF;
+    INFO("blitbit(%d,%d, %d,%d, %02X) [%04X,%04X]", x,y, w,h, *color, _foreground, _background);
+    INFO("%lu  %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X",
+        color,
+        color[0], color[1], color[2], color[3], color[4], color[5], color[6], color[7], 
+        color[8], color[9], color[10], color[11], color[12], color[13], color[14], color[15]);
+    window(x, y, w, h);
+    _StartGraphicsStream();
+    for (int i = 0; i < w*h; i++) {
+        char byte = color[i >> 3];
+        int offset = i & 0x7;
+        if (offset == 0)
+            INFO(" %2d = %02X", i>>3, byte);
+        int c = ((byte << offset) & 0x80) ? _foreground : _background;
+        _putp(c);
+    }
+    _EndGraphicsStream();
+    WindowMax();
+    return w;
+}
+#endif
+
+
+int GraphicsDisplay::fontblit(int x, int y, const unsigned char * fontTable, const unsigned char * fontChar)
+{
+    //int fontWidth = font[1];                       // get hor size of font
+    int fontHeight = font[2];                      // get vert size of font
+    int bytesPerLine = font[3];                       // bytes per line
+    int charWidth = fontChar[0];        // width of this character
+    int px, py;
+    
+    //INFO("(%d,%d) %lu, %lu %X/%X", x,y, fontTable, fontChar, _foreground, _background);
+    //INFO("char size (%d,%d)", charWidth, fontHeight);
+    //HexDump("char", (uint8_t *)fontChar, 32);
+    //INFO("(f,b) = (%04X,%04X)", _foreground, _background)
+    window(x, y, charWidth, fontHeight);
+    _StartGraphicsStream();
+    //INFO("(f,b) = (%04X,%04X)", _foreground, _background)
+    for (py = 0; py < fontHeight; py++) {
+        int bitmask = 1 << (py & 7);
+        
+        for (px = 0; px < charWidth; px++) {
+            int offset = (py / 8) + px * bytesPerLine;
+            unsigned char byte = fontChar[offset + 1];  // skip the char's # bits wide value
+            color_t c = (byte & bitmask) ? _foreground : _background;
+            //INFO("(%2d,%2d) %02X & %02X => %04X [%04X,%04X]", px, py, byte, bitmask, c, _foreground, _background);
+            //pixel(x+px, y+py, c);
+            _putp(c);
+        }
+    }
+    _EndGraphicsStream();
+    WindowMax();
+    return charWidth;
+}
+
+// BMP Color Palette is BGRx
+//      BBBB BBBB GGGG GGGG RRRR RRRR 0000 0000
+// RGB16 is
+//      RRRR RGGG GGGB BBBB
+// swap to little endian
+//      GGGB BBBB RRRR RGGG
+color_t GraphicsDisplay::RGBQuadToRGB16(RGBQUAD * colorPalette, uint16_t i)
+{
+    color_t c;
+ 
+    c  = ((colorPalette[i].rgbBlue  >> 3) <<  0);
+    c |= ((colorPalette[i].rgbGreen >> 2) <<  5);
+    c |= ((colorPalette[i].rgbRed   >> 3) << 11);
+    return c;
+}
+
+/// RRRR RGGG GGGB BBBB
+RGBQUAD GraphicsDisplay::RGB16ToRGBQuad(color_t c)
+{
+    RGBQUAD q;
+    
+    memset(&q, 0, sizeof(q));
+    q.rgbBlue  = ((c & 0x001F) << 3) | (c & 0x07);          /* Blue value */
+    q.rgbGreen = ((c & 0x07E0) >> 3) | ((c >> 7) & 0x03);   /* Green value */
+    q.rgbRed   = ((c & 0xF800) >> 8) | ((c >> 11) & 0x07);  /* Red value */
+    q.rgbReserved = 0;
+    return q;
+}
+
+RetCode_t GraphicsDisplay::_RenderBitmap(loc_t x, loc_t y, uint32_t fileOffset, FILE * Image)
+{
+    BITMAPINFOHEADER BMP_Info;
+    RGBQUAD * colorPalette = NULL;
+    int colorCount;
+    uint8_t * lineBuffer = NULL;
+    color_t * pixelBuffer = NULL;
+    uint16_t BPP_t;
+    uint32_t PixelWidth, PixelHeight;
+    unsigned int    i, offset;
+    int padd,j;
+    #ifdef DEBUG
+    uint32_t start_data;
+    #endif
+
+    // Now, Read the bitmap info header
+    fread(&BMP_Info, 1, sizeof(BMP_Info), Image);
+    HexDump("BMP_Info", (uint8_t *)&BMP_Info, sizeof(BMP_Info));
+    BPP_t = BMP_Info.biBitCount;
+    INFO("biBitCount %04X", BPP_t);
+    if (BPP_t != 4 && BPP_t != 8 && BPP_t != 16 && BPP_t != 24) { // Support 4, 8, 16, 24-bits per pixel
+        fclose(Image);
+        return(not_supported_format);
+    }
+
+    PixelHeight = BMP_Info.biHeight;
+    PixelWidth = BMP_Info.biWidth;
+    INFO("(%d,%d) (%d,%d) (%d,%d)", x,y, PixelWidth,PixelHeight, width(), height());
+    if (PixelHeight > height() + y || PixelWidth > width() + x) {
+        fclose(Image);
+        return(image_too_big);
+    }
+    if (BMP_Info.biBitCount <= 8) {
+        int paletteSize;
+        // Read the color palette
+        colorCount = 1 << BMP_Info.biBitCount;
+        paletteSize = sizeof(RGBQUAD) * colorCount;
+        colorPalette = (RGBQUAD *)malloc(paletteSize);
+        if (colorPalette == NULL) {
+            fclose(Image);
+            return(not_enough_ram);
+        }
+        fread(colorPalette, 1, paletteSize, Image);
+        HexDump("Color Palette", (uint8_t *)colorPalette, paletteSize);
+    }
+
+    int lineBufSize = ((BPP_t * PixelWidth + 7)/8);
+    INFO("BPP_t %d, PixelWidth %d, lineBufSize %d", BPP_t, PixelWidth, lineBufSize);
+    lineBuffer = (uint8_t *)malloc(lineBufSize);
+    if (lineBuffer == NULL) {
+        free(colorPalette);
+        fclose(Image);
+        return(not_enough_ram);
+    }
+    pixelBuffer = (color_t *)malloc(PixelWidth * sizeof(color_t));
+    if (pixelBuffer == NULL) {
+        free(lineBuffer);
+        if (colorPalette)
+            free(colorPalette);
+        fclose(Image);
+        return(not_enough_ram);
+    }
+
+    // the Raw Data records are padded to a multiple of 4 bytes
+    int recordSize = 2;
+    if (BPP_t == 4) {
+        recordSize = 1;
+    } else if (BPP_t == 8) {
+        recordSize = 1;
+    } else if (BPP_t == 16) {
+        recordSize = 2;
+    } else if (BPP_t == 24) {
+        recordSize = 3;
+    }
+    padd = -1;
+    do {
+        padd++;
+    } while ((PixelWidth * recordSize + padd) % 4 != 0);
+
+    // Define window for top to bottom and left to right so writing auto-wraps
+    window(x,y, PixelWidth,PixelHeight);
+    SetGraphicsCursor(x, y);
+    _StartGraphicsStream();
+    
+    //start_data = BMP_Header.bfOffBits;
+    HexDump("Raw Data", (uint8_t *)&start_data, 32);
+    INFO("(%d,%d) (%d,%d), [%d,%d]", x,y, PixelWidth,PixelHeight, lineBufSize, padd);
+    for (j = PixelHeight - 1; j >= 0; j--) {                //Lines bottom up
+        offset = fileOffset + j * (lineBufSize + padd);     // start of line
+        fseek(Image, offset, SEEK_SET);
+        fread(lineBuffer, 1, lineBufSize, Image);           // read a line - slow !
+        //INFO("offset: %6X", offset);
+        for (i = 0; i < PixelWidth; i++) {                  // copy pixel data to TFT
+            if (BPP_t == 4) {
+                uint8_t dPix = lineBuffer[i/2];
+                if ((i & 1) == 0)
+                    dPix >>= 4;
+                dPix &= 0x0F;
+                pixelBuffer[i] = RGBQuadToRGB16(colorPalette, dPix);
+            } else if (BPP_t == 8) {
+                pixelBuffer[i] = RGBQuadToRGB16(colorPalette, lineBuffer[i]);
+            } else if (BPP_t == 16) {
+                pixelBuffer[i] = lineBuffer[i];
+            } else if (BPP_t == 24) {
+                color_t color;
+                color = RGB(lineBuffer[i*3+2], lineBuffer[i*3+1], lineBuffer[i*3+0]);
+                pixelBuffer[i] = color;
+            }
+        }
+        pixelStream(pixelBuffer, PixelWidth, x, y++);
+    }
+    _EndGraphicsStream();
+    WindowMax();
+    free(pixelBuffer);      // don't leak memory
+    free(lineBuffer);
+    if (colorPalette)
+        free(colorPalette);
+    return (noerror);
+}
+
+
+RetCode_t GraphicsDisplay::RenderImageFile(loc_t x, loc_t y, const char *FileName)
+{
+    if (mystrnicmp(FileName + strlen(FileName) - 4, ".bmp", 4) == 0) {
+        return RenderBitmapFile(x,y,FileName);
+    } else if (mystrnicmp(FileName + strlen(FileName) - 4, ".ico", 4) == 0) {
+        return RenderIconFile(x,y,FileName);
+    } else {
+        return not_supported_format;
+    }
+}
+
+RetCode_t GraphicsDisplay::RenderBitmapFile(loc_t x, loc_t y, const char *Name_BMP)
+{
+    BITMAPFILEHEADER BMP_Header;
+
+    INFO("Opening {%s}", Name_BMP);
+    FILE *Image = fopen(Name_BMP, "rb");
+    if (!Image) {
+        return(file_not_found);
+    }
+
+    fread(&BMP_Header, 1, sizeof(BMP_Header), Image);      // get the BMP Header
+    INFO("bfType %04X", BMP_Header.bfType);
+    HexDump("BMP_Header", (uint8_t *)&BMP_Header, sizeof(BMP_Header));
+    if (BMP_Header.bfType != BF_TYPE) {
+        fclose(Image);
+        return(not_bmp_format);
+    }
+    RetCode_t rt = _RenderBitmap(x, y, BMP_Header.bfOffBits, Image);
+    if (rt != noerror) {
+        return rt;
+    } else {
+        fclose(Image);
+        return (noerror);
+    }
+}
+
+RetCode_t GraphicsDisplay::RenderIconFile(loc_t x, loc_t y, const char *Name_ICO)
+{
+    ICOFILEHEADER ICO_Header;
+    ICODIRENTRY ICO_DirEntry;
+
+    INFO("Opening {%s}", Name_ICO);
+    FILE *Image = fopen(Name_ICO, "rb");
+    if (!Image) {
+        return(file_not_found);
+    }
+
+    fread(&ICO_Header, 1, sizeof(ICO_Header), Image);      // get the BMP Header
+    HexDump("ICO_Header", (uint8_t *)&ICO_Header, sizeof(ICO_Header));
+    if (ICO_Header.Reserved_zero != 0
+    || ICO_Header.icType != IC_TYPE
+    || ICO_Header.icImageCount == 0) {
+        fclose(Image);
+        return(not_ico_format);
+    }
+
+    // Read ONLY the first of n possible directory entries.
+    fread(&ICO_DirEntry, 1, sizeof(ICO_DirEntry), Image);
+    HexDump("ICO_DirEntry", (uint8_t *)&ICO_DirEntry, sizeof(ICO_DirEntry));
+    INFO("biBitCount %04X", ICO_DirEntry.biBitCount);
+    if (ICO_DirEntry.biBitCount != 0) {     // Expecting this to be zero for ico
+        fclose(Image);
+        return(not_supported_format);
+    }
+
+    RetCode_t rt = _RenderBitmap(x, y, ICO_DirEntry.bfOffBits, Image);
+    if (rt == noerror) {
+        fclose(Image);
+        return (noerror);
+    } else {
+        return rt;
+    }
+}
+
+int GraphicsDisplay::columns()
+{
+    return width() / 8;
+}
+
+int GraphicsDisplay::rows()
+{
+    return height() / 8;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/RA8875/GraphicsDisplay.h	Mon Nov 30 11:13:18 2015 +0000
@@ -0,0 +1,428 @@
+/* mbed GraphicsDisplay Display Library Base Class
+ * Copyright (c) 2007-2009 sford
+ * Released under the MIT License: http://mbed.org/license/mit
+ *
+ * A library for providing a common base class for Graphics displays
+ * To port a new display, derive from this class and implement
+ * the constructor (setup the display), pixel (put a pixel
+ * at a location), width and height functions. Everything else
+ * (locate, printf, putc, cls, window, putp, fill, blit, blitbit) 
+ * will come for free. You can also provide a specialised implementation
+ * of window and putp to speed up the results
+ */
+
+#ifndef MBED_GRAPHICSDISPLAY_H
+#define MBED_GRAPHICSDISPLAY_H
+#include "Bitmap.h"
+#include "TextDisplay.h"
+
+// GraphicsDisplay has one "soft font" which is in a different format
+// then the primary font rendering api - see set_font(...). This is
+// therefore deprecated, but preserved for a time for backward 
+// compatibility.
+// #define LOCALFONT
+
+
+/// The GraphicsDisplay class 
+/// 
+/// This graphics display class supports both graphics and text operations.
+/// Typically, a subclass is derived from this which has localizations to
+/// adapt to a specific hardware platform (e.g. a display controller chip),
+/// that overrides methods in here to either add more capability or perhaps 
+/// to improve performance, by leveraging specific hardware capabilities.
+///
+class GraphicsDisplay : public TextDisplay 
+{
+public:
+    /// The constructor
+    GraphicsDisplay(const char* name);
+    
+    /// Draw a pixel in the specified color.
+    ///
+    /// @note this method must be supported in the derived class.
+    ///
+    /// @param[in] x is the horizontal offset to this pixel.
+    /// @param[in] y is the vertical offset to this pixel.
+    /// @param[in] color defines the color for the pixel.
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    virtual RetCode_t pixel(loc_t x, loc_t y, color_t color) = 0;
+    
+    /// Write a stream of pixels to the display.
+    ///
+    /// @note this method must be supported in the derived class.
+    ///
+    /// @param[in] p is a pointer to a color_t array to write.
+    /// @param[in] count is the number of pixels to write.
+    /// @param[in] x is the horizontal position on the display.
+    /// @param[in] y is the vertical position on the display.
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    virtual RetCode_t pixelStream(color_t * p, uint32_t count, loc_t x, loc_t y) = 0;
+
+    /// Get a pixel from the display.
+    ///
+    /// @note this method must be supported in the derived class.
+    ///
+    /// @param[in] x is the horizontal offset to this pixel.
+    /// @param[in] y is the vertical offset to this pixel.
+    /// @returns the pixel. see @color_t
+    ///
+    virtual color_t getPixel(loc_t x, loc_t y) = 0;
+
+    /// Get a stream of pixels from the display.
+    ///
+    /// @note this method must be supported in the derived class.
+    ///
+    /// @param[out] p is a pointer to a color_t array to accept the stream.
+    /// @param[in] count is the number of pixels to read.
+    /// @param[in] x is the horizontal offset to this pixel.
+    /// @param[in] y is the vertical offset to this pixel.
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    virtual RetCode_t getPixelStream(color_t * p, uint32_t count, loc_t x, loc_t y) = 0;
+    
+    /// get the screen width in pixels
+    ///
+    /// @note this method must be supported in the derived class.
+    ///
+    /// @returns screen width in pixels.
+    ///
+    virtual uint16_t width() = 0;
+    
+    /// get the screen height in pixels
+    ///
+    /// @note this method must be supported in the derived class.
+    ///
+    /// @returns screen height in pixels.
+    ///
+    virtual uint16_t height() = 0;
+
+    /// Prepare the controller to write binary data to the screen by positioning
+    /// the memory cursor.
+    ///
+    /// @note this method must be supported in the derived class.
+    ///
+    /// @param[in] x is the horizontal position in pixels (from the left edge)
+    /// @param[in] y is the vertical position in pixels (from the top edge)
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    virtual RetCode_t SetGraphicsCursor(loc_t x, loc_t y) = 0;
+    
+    /// Prepare the controller to read binary data from the screen by positioning
+    /// the memory read cursor.
+    ///
+    /// @param[in] x is the horizontal position in pixels (from the left edge)
+    /// @param[in] y is the vertical position in pixels (from the top edge)
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    virtual RetCode_t SetGraphicsCursorRead(loc_t x, loc_t y) = 0;
+    
+    /// Draw a filled rectangle in the specified color
+    ///
+    /// @note As a side effect, this changes the current
+    ///     foreground color for subsequent operations.
+    ///
+    /// @note this method must be supported in the derived class.
+    ///
+    /// @param[in] x1 is the horizontal start of the line.
+    /// @param[in] y1 is the vertical start of the line.
+    /// @param[in] x2 is the horizontal end of the line.
+    /// @param[in] y2 is the vertical end of the line.
+    /// @param[in] color defines the foreground color.
+    /// @param[in] fillit is optional to NOFILL the rectangle. default is FILL.
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    virtual RetCode_t fillrect(loc_t x1, loc_t y1, loc_t x2, loc_t y2, 
+        color_t color, fill_t fillit = FILL) = 0;
+
+
+    virtual RetCode_t WriteCommand(unsigned char command, unsigned int data = 0xFFFF) = 0;
+    virtual RetCode_t WriteData(unsigned char data) = 0;
+
+    /// Set the window, which controls where items are written to the screen.
+    ///
+    /// When something hits the window width, it wraps back to the left side
+    /// and down a row. If the initial write is outside the window, it will
+    /// be captured into the window when it crosses a boundary.
+    ///
+    /// @param[in] x is the left edge in pixels.
+    /// @param[in] y is the top edge in pixels.
+    /// @param[in] w is the window width in pixels.
+    /// @param[in] h is the window height in pixels.
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    virtual RetCode_t window(loc_t x, loc_t y, dim_t w, dim_t h);
+    
+    /// Clear the screen.
+    ///
+    /// The behavior is to clear the whole screen.
+    ///
+    /// @param[in] layers is ignored, but supports maintaining the same 
+    ///     API for the graphics layer.
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    virtual RetCode_t cls(uint16_t layers = 0);
+    
+    /// method to set the window region to the full screen.
+    ///
+    /// This restores the 'window' to the full screen, so that 
+    /// other operations (@see cls) would clear the whole screen.
+    ///
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    virtual RetCode_t WindowMax(void);
+    
+    /// method to put a single color pixel to the screen.
+    ///
+    /// This method may be called as many times as necessary after 
+    /// @see _StartGraphicsStream() is called, and it should be followed 
+    /// by _EndGraphicsStream.
+    ///
+    /// @param[in] pixel is a color value to be put on the screen.
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    virtual RetCode_t _putp(color_t pixel);
+
+    /// method to fill a region.
+    ///
+    /// This method fills a region with the specified color.
+    ///
+    /// @param[in] x is the left-edge of the region.
+    /// @param[in] y is the top-edge of the region.
+    /// @param[in] w specifies the width of the region.
+    /// @param[in] h specifies the height of the region.
+    /// @returns success/failure code. @see RetCode_t.
+    /// 
+    virtual RetCode_t fill(int x, int y, int w, int h, color_t color);
+    
+    
+    virtual RetCode_t blit(int x, int y, int w, int h, const int * color);    
+    
+    /// This method transfers one character from the external font data
+    /// to the screen.
+    ///
+    /// @note the font data is in a special format as generate by
+    ///         the mikroe font creator. \\
+    ///         See http://www.mikroe.com/glcd-font-creator/
+    ///
+    /// @param[in] x is the horizontal pixel coordinate
+    /// @param[in] y is the vertical pixel coordinate
+    /// @param[in] fontTable is the base of the table which has the metrics
+    /// @param[in] fontChar is the start of that record in the table for the char (e.g. 'A' - 'Z')
+    /// @returns how far the cursor should advance to the right in pixels
+    ///
+    virtual int fontblit(int x, int y, const unsigned char * fontTable, const unsigned char * fontChar);
+    
+    /// This method returns the color value from a palette.
+    ///
+    /// This method accepts a pointer to a Bitmap color palette, which
+    /// is a table in memory composed of RGB Quad values (r, g, b, 0),
+    /// and an index into that table. It then extracts the color information
+    /// and downsamples it to a color_t value which it returns.
+    ///
+    /// @note This method probably has very little value outside of
+    ///         the internal methods for reading BMP files.
+    ///
+    /// @param[in] colorPaletteArray is the handle to the color palette array to use.
+    /// @param[in] index is the index into the color palette.
+    /// @returns the color in color_t format.
+    ///
+    color_t RGBQuadToRGB16(RGBQUAD * colorPaletteArray, uint16_t index);
+    
+    /// This method converts a 16-bit color value into a 24-bit RGB Quad.
+    ///
+    /// @param[in] c is the 16-bit color. @see color_t.
+    /// @returns an RGBQUAD value. @see RGBQUAD
+    ///
+    RGBQUAD RGB16ToRGBQuad(color_t c);
+
+    /// This method attempts to render a specified graphics image file at
+    /// the specified screen location.
+    ///
+    /// This supports several variants of the following file types:
+    /// \li Bitmap file format,
+    /// \li Icon file format.
+    ///
+    /// @note The specified image width and height, when adjusted for the 
+    ///     x and y origin, must fit on the screen, or the image will not
+    ///     be shown (it does not clip the image).
+    ///
+    /// @note The file extension is tested, and if it ends in a supported
+    ///     format, the appropriate handler is called to render that image.
+    ///
+    /// @param[in] x is the horizontal pixel coordinate
+    /// @param[in] y is the vertical pixel coordinate
+    /// @param[in] FileName refers to the fully qualified path and file on 
+    ///     a mounted file system.
+    /// @returns success or error code.
+    ///
+    RetCode_t RenderImageFile(loc_t x, loc_t y, const char *FileName);
+
+    /// This method reads a disk file that is in bitmap format and 
+    /// puts it on the screen.
+    ///
+    /// Supported formats:
+    /// \li 4-bit color format (16 colors)
+    /// \li 8-bit color format (256 colors)
+    /// \li 16-bit color format (65k colors)
+    /// \li compression: no.
+    ///
+    /// @note This is a slow operation, typically due to the use of
+    ///         the file system, and partially because bmp files
+    ///         are stored from the bottom up, and the memory is written
+    ///         from the top down; as a result, it constantly 'seeks'
+    ///         on the file system for the next row of information.
+    ///
+    /// As a performance test, a sample picture was timed. A family picture
+    /// was converted to Bitmap format; shrunk to 352 x 272 pixels and save
+    /// in 8-bit color format. The resulting file size was 94.5 KByte.
+    /// The SPI port interface was set to 20 MHz.
+    /// The original bitmap rendering software was purely in software, 
+    /// pushing 1 pixel at a time to the write function, which did use SPI
+    /// hardware (not pin wiggling) to transfer commands and data to the 
+    /// display. Then, the driver was improved to leverage the capability
+    /// of the derived display driver. As a final check, instead of the
+    /// [known slow] local file system, a randomly chosen USB stick was 
+    /// used. The performance results are impressive (but depend on the
+    /// listed factors). 
+    ///
+    /// \li 34 seconds, LocalFileSystem, Software Rendering
+    /// \li 9 seconds, LocalFileSystem, Hardware Rending for RA8875
+    /// \li 3 seconds, MSCFileSystem, Hardware Rendering for RA8875
+    /// 
+    /// @param[in] x is the horizontal pixel coordinate
+    /// @param[in] y is the vertical pixel coordinate
+    /// @param[in] Name_BMP is the filename on the mounted file system.
+    /// @returns success or error code.
+    ///
+    RetCode_t RenderBitmapFile(loc_t x, loc_t y, const char *Name_BMP);
+    
+    
+    /// This method reads a disk file that is in ico format and 
+    /// puts it on the screen.
+    ///
+    /// Reading the disk is slow, but a typical icon file is small
+    /// so it should be ok.
+    ///
+    /// @note An Icon file can have more than one icon in it. This
+    ///     implementation only processes the first image in the file.
+    ///
+    /// @param[in] x is the horizontal pixel coordinate
+    /// @param[in] y is the vertical pixel coordinate
+    /// @param[in] Name_ICO is the filename on the mounted file system.
+    /// @returns success or error code.
+    ///
+    RetCode_t RenderIconFile(loc_t x, loc_t y, const char *Name_ICO);
+
+    
+    /// prints one character at the specified coordinates.
+    ///
+    /// This will print the character at the specified pixel coordinates.
+    ///
+    /// @param[in] x is the horizontal offset in pixels.
+    /// @param[in] y is the vertical offset in pixels.
+    /// @param[in] value is the character to print.
+    /// @returns number of pixels to index to the right if a character was printed, 0 otherwise.
+    ///
+    virtual int character(int x, int y, int value);
+    
+    /// get the number of colums based on the currently active font
+    ///
+    /// @returns number of columns.
+    ///    
+    virtual int columns(void);
+
+    /// get the number of rows based on the currently active font
+    ///
+    /// @returns number of rows.
+    ///    
+    virtual int rows(void);
+    
+    /// Select a bitmap font (provided by the user) for all subsequent text
+    /// rendering.
+    ///
+    /// This API permits selection of a special memory mapped font, which 
+    /// enables the presentation of many font sizes and styles, including
+    /// proportional fonts.
+    ///
+    /// @note Tool to create the fonts is accessible from its creator
+    ///     available at http://www.mikroe.com.
+    ///     Hint: Change the data to an array of type char[].
+    ///
+    ///     This special font array has a 4-byte header, followed by 
+    ///     the data:
+    ///   \li the number of bytes per char
+    ///   \li the vertical size in pixels for each character
+    ///   \li the horizontal size in pixels for each character
+    ///   \li the number of bytes per vertical line (width of the array)
+    ///   \li the subsequent records are the font information.
+    ///
+    /// @param[in] font is a pointer to a specially formed font array. 
+    ///     NULL, or the omission of this parameter will restore the default
+    ///     font capability, which may use the display controllers hardware
+    ///     font (if available), or no font.
+    /// @returns error code.
+    ///
+    virtual RetCode_t set_font(const unsigned char * font = NULL);
+
+protected:
+
+    /// Pure virtual method indicating the start of a graphics stream.
+    ///
+    /// This is called prior to a stream of pixel data being sent.
+    /// This may cause register configuration changes in the derived
+    /// class in order to prepare the hardware to accept the streaming
+    /// data.
+    ///
+    /// @note this method must be supported in the derived class.
+    ///
+    /// @returns error code.
+    ///
+    virtual RetCode_t _StartGraphicsStream(void) = 0;
+    
+    /// Pure virtual method indicating the end of a graphics stream.
+    ///
+    /// This is called to conclude a stream of pixel data that was sent.
+    /// This may cause register configuration changes in the derived
+    /// class in order to stop the hardware from accept the streaming
+    /// data.
+    ///
+    /// @note this method must be supported in the derived class.
+    ///
+    /// @returns error code.
+    ///
+    virtual RetCode_t _EndGraphicsStream(void) = 0;
+
+    /// Protected method to render an image given a file handle and 
+    /// coordinates.
+    ///
+    /// @param[in] x is the horizontal pixel coordinate
+    /// @param[in] y is the vertical pixel coordinate
+    /// @param[in] w is the image width restriction, or zero to permit full image width.
+    /// @param[in] h is the image height restriction, or zero to permit full image height.
+    /// @param[in] fileOffset is the offset into the file where the image data starts
+    /// @param[in] Image is the filename stream already opened for the data.
+    /// @returns success or error code.
+    ///
+    RetCode_t _RenderBitmap(loc_t x, loc_t y, uint32_t fileOffset, FILE * Image);
+
+    #ifdef LOCALFONT
+    virtual int blitbit(int x, int y, int w, int h, const char * color);
+    #endif
+    
+    const unsigned char * font;     ///< reference to an external font somewhere in memory
+    
+    // pixel location
+    short _x;
+    short _y;
+    
+    // window location
+    short _x1;
+    short _x2;
+    short _y1;
+    short _y2;
+};
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/RA8875/RA8875.cpp	Mon Nov 30 11:13:18 2015 +0000
@@ -0,0 +1,2462 @@
+/// RA8875 Display Controller Library.
+///
+/// This is being created for a Raio RA8875-based display from buydisplay.com,
+/// which is 480 x 272 using a 4-wire SPI interface. Support is provided for
+/// both a keypad and a resistive touch-screen.
+///
+/// This display controller is used in other display resolutions, up to 800x600.
+/// While this driver has not been tested with these variants, nothing was done
+/// to prevent easily supporting them.
+///
+#include "RA8875.h"
+
+//#define DEBUG "RAIO"
+// ...
+// INFO("Stuff to show %d", var); // new-line is automatically appended
+//
+#if (defined(DEBUG) && !defined(TARGET_LPC11U24))
+#define INFO(x, ...) std::printf("[INF %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
+#define WARN(x, ...) std::printf("[WRN %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
+#define ERR(x, ...)  std::printf("[ERR %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
+static void HexDump(char * title, uint8_t * p, int count)
+{
+    int i;
+    char buf[100] = "0000: ";
+
+    if (*title)
+        INFO("%s", title);
+    for (i=0; i<count; ) {
+        sprintf(buf + strlen(buf), "%02X ", *(p+i));
+        if ((++i & 0x0F) == 0x00) {
+            INFO("%s", buf);
+            if (i < count)
+                sprintf(buf, "%04X: ", i);
+            else
+                buf[0] = '\0';
+        }
+    }
+    if (strlen(buf))
+        INFO("%s", buf);
+}
+#else
+#define INFO(x, ...)
+#define WARN(x, ...)
+#define ERR(x, ...)
+#define HexDump(a, b, c)
+#endif
+
+
+#define RA8875_DISPLAY_WIDTH  480
+#define RA8875_DISPLAY_HEIGHT 272
+#define RA8875_COLORDEPTH_BPP 16    /* Not an API */
+
+#ifdef PERF_METRICS
+#define PERFORMANCE_RESET performance.reset()
+#define REGISTERPERFORMANCE(a) RegisterPerformance(a)
+#define COUNTIDLETIME(a) CountIdleTime(a)
+static const char *metricsName[] = {
+    "Cls", "Pixel", "Pixel Stream",
+    "Read Pixel", "Read Pixel Stream",
+    "Line",
+    "Rectangle", "Rounded Rectangle",
+    "Triangle", "Circle", "Ellipse"
+};
+#else
+#define PERFORMANCE_RESET
+#define REGISTERPERFORMANCE(a)
+#define COUNTIDLETIME(a)
+#endif
+
+// When it is going to poll a register for completion, how many
+// uSec should it wait between each polling activity.
+#define POLLWAITuSec 10
+
+// Private RawKeyMap for the Keyboard interface
+static const uint8_t DefaultKeyMap[22] = {
+    0,
+    1,  2,  3,  4,  5,  6,  7,  8,  9, 10,
+    11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
+    255
+};
+
+static const char * ErrMessages[] = {
+    "noerror",                ///< no errors, command completed successfully
+    "bad_parameter",          ///< one or more parameters are invalid
+    "file_not_found",         ///< specified file could not be found
+    "not_bmp_format",         ///< file is not a .bmp file
+    "not_ico_format",         ///< file is not a .ico file
+    "not_supported_format",   ///< file format is not yet supported
+    "image_too_big",          ///< image is too large for the screen
+    "not_enough_ram",         ///< could not allocate ram for scanline
+};
+
+RA8875::RA8875(PinName mosi, PinName miso, PinName sclk, PinName csel, PinName reset, const char *name)
+    : GraphicsDisplay(name)
+    , spi(mosi, miso, sclk)
+    , cs(csel)
+    , res(reset)
+{
+}
+
+//RA8875::~RA8875()
+//{
+//}
+
+RetCode_t RA8875::init(int width, int height, int color_bpp, bool poweron, bool keypadon, bool touchscreenon)
+{
+    font = NULL;                        // no external font, use internal.
+    pKeyMap = DefaultKeyMap;            // set default key map
+    _select(false);                      // deselect the display
+    frequency(RA8875_DEFAULT_SPI_FREQ); // data rate
+    Reset();
+    WriteCommand(0x88, 0x0B);                   // PLLC1 - Phase Lock Loop registers
+    wait_ms(1);
+    WriteCommand(0x89, 0x02);
+    wait_ms(1);
+
+    // System Config Register (SYSR)
+    if (color_bpp == 16) {
+        WriteCommand(0x10, 0x0C);               // 16-bpp (65K colors) color depth, 8-bit interface
+    } else { // color_bpp == 8
+        WriteCommand(0x10, 0x00);               // 8-bpp (256 colors)
+    }
+    // Pixel Clock Setting Register (PCSR)
+    WriteCommand(0x04, 0x82);                   // PDAT on PCLK falling edge, PCLK = 4 x System Clock
+    wait_ms(1);
+
+    // Horizontal Settings
+    WriteCommand(0x14, width/8 - 1);            //HDWR//Horizontal Display Width Setting Bit[6:0]
+    WriteCommand(0x15, 0x02);                   //HNDFCR//Horizontal Non-Display Period fine tune Bit[3:0]
+    WriteCommand(0x16, 0x03);                   //HNDR//Horizontal Non-Display Period Bit[4:0]
+    WriteCommand(0x17, 0x01);                   //HSTR//HSYNC Start Position[4:0]
+    WriteCommand(0x18, 0x03);                   //HPWR//HSYNC Polarity ,The period width of HSYNC.
+
+    // Vertical Settings
+    WriteCommand(0x19, (height-1)&0xFF);        //VDHR0 //Vertical Display Height Bit [7:0]
+    WriteCommand(0x1a, (height-1)>>8);          //VDHR1 //Vertical Display Height Bit [8]
+    WriteCommand(0x1b, 0x0F);                   //VNDR0 //Vertical Non-Display Period Bit [7:0]
+    WriteCommand(0x1c, 0x00);                   //VNDR1 //Vertical Non-Display Period Bit [8]
+    WriteCommand(0x1d, 0x0e);                   //VSTR0 //VSYNC Start Position[7:0]
+    WriteCommand(0x1e, 0x06);                   //VSTR1 //VSYNC Start Position[8]
+    WriteCommand(0x1f, 0x01);                   //VPWR //VSYNC Polarity ,VSYNC Pulse Width[6:0]
+
+    if (width >= 800 && height >= 480 && color_bpp > 8) {
+        WriteCommand(0x20, 0x00);               // DPCR - 1-layer mode when the resolution is too high
+    } else {
+        WriteCommand(0x20, 0x80);               // DPCR - 2-layer mode
+    }
+
+    // Set display image to Blue on Black as default
+    window(0,0, width, height);             // Initialize to full screen
+    SetTextCursorControl();
+    foreground(Blue);
+    background(Black);
+    cls(3);
+
+    Power(poweron);
+    if (poweron)
+        Backlight_u8(255);
+    if (keypadon)
+        KeypadInit();
+    if (touchscreenon)
+        TouchPanelInit();
+#ifdef PERF_METRICS
+    performance.start();
+    ClearPerformance();
+#endif
+    return noerror;
+}
+
+
+RetCode_t RA8875::Reset(void)
+{
+    RetCode_t ret;
+    
+    ret = WriteCommand(0x01, 0x01);   // Apply Display Off, Reset
+    wait_ms(2);                     // no idea if I need to wait, or how long
+    if (ret == noerror) {
+        ret = WriteCommand(0x01, 0x00);   // Display off, Remove reset
+        wait_ms(2);                     // no idea if I need to wait, or how long
+    }
+    return ret;
+}
+
+
+const char * RA8875::GetErrorMessage(RetCode_t code)
+{
+    if (code >= LastErrCode)
+        code = bad_parameter;
+    return ErrMessages[code];
+}
+
+
+uint16_t RA8875::GetDrawingLayer(void)
+{
+    return (ReadCommand(0x41) & 0x01);
+}
+
+
+RetCode_t RA8875::SelectDrawingLayer(uint16_t layer)
+{
+    unsigned char mwcr1 = ReadCommand(0x41) & ~0x01; // retain all but the currently selected layer
+
+    if (width() >= 800 && height() >= 480 && color_bpp() == 8) {
+        return bad_parameter;
+    } else if (layer > 1) {
+        return bad_parameter;
+    } else { // layer == 0 ro 1
+        return WriteCommand(0x41, mwcr1 | layer);
+    }
+}
+
+
+RetCode_t RA8875::SetLayerMode(LayerMode_T mode)
+{
+    unsigned char ltpr0 = ReadCommand(0x52) & ~0x7; // retain all but the display layer mode
+    if (mode <= (LayerMode_T)6) {
+        WriteCommand(0x52, ltpr0 | (mode & 0x7));
+        return noerror;
+    } else {
+        return bad_parameter;
+    }
+}
+
+
+RetCode_t RA8875::SetLayerTransparency(uint8_t layer1, uint8_t layer2)
+{
+    if (layer1 > 8)
+        layer1 = 8;
+    if (layer2 > 8)
+        layer2 = 8;
+    WriteCommand(0x53, ((layer2 & 0xF) << 4) | (layer1 & 0xF));
+    return noerror;
+}
+
+
+RetCode_t RA8875::SetBackgroundTransparencyColor(color_t color)
+{
+    WriteCommand(0x67, (color >> 11) & 0x1F);
+    WriteCommand(0x68, (color >> 5) & 0x3F);
+    WriteCommand(0x69, (color & 0x1F));
+    return noerror;
+}
+
+
+color_t RA8875::GetBackgroundTransparencyColor(void)
+{
+    RGBQUAD q;
+    q.rgbRed = ReadCommand(0x67);
+    q.rgbGreen = ReadCommand(0x68);
+    q.rgbBlue = ReadCommand(0x69);
+    return RGBQuadToRGB16(&q, 0);
+}
+
+
+RetCode_t RA8875::KeypadInit(bool scanEnable, bool longDetect, uint8_t sampleTime, uint8_t scanFrequency,
+                             uint8_t longTimeAdjustment, bool interruptEnable, bool wakeupEnable)
+{
+    uint8_t value = 0;
+
+    if (sampleTime > 3 || scanFrequency > 7 || longTimeAdjustment  > 3)
+        return bad_parameter;
+    value |= (scanEnable) ? 0x80 : 0x00;
+    value |= (longDetect) ? 0x40 : 0x00;
+    value |= (sampleTime & 0x03) << 4;
+    value |= (scanFrequency & 0x07);
+    WriteCommand(0xC0, value);   // KSCR1 - Enable Key Scan (and ignore possibility of an error)
+
+    value = 0;
+    value |= (wakeupEnable) ? 0x80 : 0x00;
+    value |= (longTimeAdjustment & 0x03) << 2;
+    WriteCommand(0xC1, value);  // KSCR2 - (and ignore possibility of an error)
+
+    value = ReadCommand(0xF0);          // (and ignore possibility of an error)
+    value &= ~0x10;
+    value |= (interruptEnable) ? 0x10 : 0x00;
+    return WriteCommand(0xF0, value);   // INT
+}
+
+
+RetCode_t RA8875::SetKeyMap(const uint8_t * CodeList)
+{
+    pKeyMap = CodeList;
+    return noerror;
+}
+
+
+bool RA8875::readable(void)
+{
+    return (ReadCommand(0xF1) & 0x10);  // check KS status - true if kbhit
+}
+
+
+uint8_t RA8875::getc(void)
+{
+    //#define GETC_DEV      // for development
+#ifdef GETC_DEV
+    uint8_t keyCode1, keyCode2;
+#endif
+    uint8_t keyCode3;
+    static uint8_t count = 0;
+    uint8_t col, row;
+    uint8_t key;
+
+    while (!readable()) {
+        wait_us(POLLWAITuSec);
+        // COUNTIDLETIME(POLLWAITuSec);     // As it is voluntary to call the getc and pend. Don't tally it.
+    }
+    // read the key press number
+    uint8_t keyNumReg = ReadCommand(0xC1) & 0x03;
+    count++;
+    switch (keyNumReg) {
+        case 0x01:      // one key
+            keyCode3 = ReadCommand(0xC2);
+#ifdef GETC_DEV
+            keyCode2 = 0;
+            keyCode1 = 0;
+#endif
+            break;
+        case 0x02:      // two keys
+            keyCode3 = ReadCommand(0xC3);
+#ifdef GETC_DEV
+            keyCode2 = ReadCommand(0xC2);
+            keyCode1 = 0;
+#endif
+            break;
+        case 0x03:      // three keys
+            keyCode3 = ReadCommand(0xC4);
+#ifdef GETC_DEV
+            keyCode2 = ReadCommand(0xC3);
+            keyCode1 = ReadCommand(0xC2);
+#endif
+            break;
+        default:         // no keys (key released)
+            keyCode3 = 0xFF;
+#ifdef GETC_DEV
+            keyCode2 = 0;
+            keyCode1 = 0;
+#endif
+            break;
+    }
+    if (keyCode3 == 0xFF)
+        key = pKeyMap[0];                    // Key value 0
+    else {
+        row = (keyCode3 >> 4) & 0x03;
+        col = (keyCode3 &  7);
+        key = row * 5 + col + 1;    // Keys value 1 - 20
+        if (key > 21) {
+            key = 21;
+        }
+        key = pKeyMap[key];
+        key |= (keyCode3 & 0x80);   // combine the key held flag
+    }
+#if GETC_DEV // for Development only
+    SetTextCursor(0, 20);
+    printf("   Reg: %02x\r\n", keyNumReg);
+    printf("  key1: %02x\r\n", keyCode1);
+    printf("  key2: %02x\r\n", keyCode2);
+    printf("  key3: %02x\r\n", keyCode3);
+    printf(" count: %02X\r\n", count);
+    printf("   key: %02X\r\n", key);
+#endif
+    WriteCommand(0xF1, 0x10);       // Clear KS status
+    return key;
+}
+
+
+#ifdef PERF_METRICS
+void RA8875::ClearPerformance()
+{
+    for (int i=0; i<METRICCOUNT; i++)
+        metrics[i] = 0;
+    idletime_usec = 0;
+}
+
+
+void RA8875::RegisterPerformance(method_e method)
+{
+    unsigned long elapsed = performance.read_us();
+
+    if (method < METRICCOUNT && elapsed > metrics[method])
+        metrics[method] = elapsed;
+}
+
+
+void RA8875::CountIdleTime(uint32_t t)
+{
+    idletime_usec += t;
+}
+
+
+void RA8875::ReportPerformance(Serial & pc)
+{
+    pc.printf("\r\nPerformance Metrics\r\n");
+    for (int i=0; i<METRICCOUNT; i++) {
+        pc.printf("%10d uS %s\r\n", metrics[i], metricsName[i]);
+    }
+    pc.printf("%10d uS Idle time polling display for ready.\r\n", idletime_usec);
+}
+#endif
+
+
+RetCode_t RA8875::WriteCommandW(uint8_t command, uint16_t data)
+{
+#if 1
+    WriteCommand(command, data & 0xFF);
+    WriteCommand(command+1, data >> 8);
+#else
+    // This should be a little faster, but doesn't work...
+    INFO("WriteCommandW(%02X, %04X)", command, data);
+    _select(true);
+    _spiwrite(0x80);
+    _spiwrite(command);
+    //_spiwrite(0x00);     // dummy
+    _spiwrite(data & 0xFF);
+    _spiwrite(data >> 8);
+    _select(false);
+#endif
+    return noerror;
+}
+
+
+RetCode_t RA8875::WriteCommand(unsigned char command, unsigned int data)
+{
+    _select(true);
+    _spiwrite(0x80);         // cmd: write command
+    _spiwrite(command);
+    if (data <= 0xFF) {   // only if in the valid range
+        _spiwrite(0x00);
+        _spiwrite(data);
+    }
+    _select(false);
+    return noerror;
+}
+
+
+RetCode_t RA8875::WriteDataW(uint16_t data)
+{
+    _select(true);
+    _spiwrite(0x00);         // cmd: write data
+    _spiwrite(data & 0xFF);
+    _spiwrite(data >> 8);
+    _select(false);
+    return noerror;
+}
+
+
+RetCode_t RA8875::WriteData(unsigned char data)
+{
+    _select(true);
+    _spiwrite(0x00);
+    _spiwrite(data);
+    _select(false);
+    return noerror;
+}
+
+
+unsigned char RA8875::ReadCommand(unsigned char command)
+{
+    WriteCommand(command);
+    return ReadData();
+}
+
+
+unsigned char RA8875::ReadData(void)
+{
+    unsigned char data;
+
+    _select(true);
+    _spiwrite(0x40);
+    data = _spiread();
+    _select(false);
+    return data;
+}
+
+
+uint16_t RA8875::ReadDataW(void)
+{
+    uint16_t data;
+
+    _select(true);
+    _spiwrite(0x40);
+    data  = _spiread();
+    data |= (_spiread() << 8);
+    _select(false);
+    return data;
+}
+
+
+unsigned char RA8875::ReadStatus(void)
+{
+    unsigned char data;
+
+    _select(true);
+    _spiwrite(0xC0);         // These two bits are for the special "Status Read" [STSR]
+    data = _spiread();
+    _select(false);
+    return data;
+}
+
+
+/// @todo add a timeout and return false, but how long
+/// to wait since some operations can be very long.
+bool RA8875::_WaitWhileBusy(uint8_t mask)
+{
+    int i = 20000/POLLWAITuSec; // 20 msec max
+
+    while (i-- && ReadStatus() & mask) {
+        wait_us(POLLWAITuSec);
+        COUNTIDLETIME(POLLWAITuSec);
+    }
+    if (i)
+        return true;
+    else
+        return false;
+}
+
+
+/// @todo add a timeout and return false, but how long
+/// to wait since some operations can be very long.
+bool RA8875::_WaitWhileReg(uint8_t reg, uint8_t mask)
+{
+    int i = 20000/POLLWAITuSec; // 20 msec max
+
+    while (i-- && ReadCommand(reg) & mask) {
+        wait_us(POLLWAITuSec);
+        COUNTIDLETIME(POLLWAITuSec);
+    }
+    if (i)
+        return true;
+    else
+        return false;
+}
+
+
+dim_t RA8875::fontwidth(void)
+{
+    if (font == NULL)
+        return (((ReadCommand(0x22) >> 2) & 0x3) + 1) * 8;
+    else
+        return font[1];
+}
+
+
+dim_t RA8875::fontheight(void)
+{
+    if (font == NULL)
+        return (((ReadCommand(0x22) >> 0) & 0x3) + 1) * 16;
+    else
+        return font[2];
+}
+
+
+RetCode_t RA8875::locate(textloc_t column, textloc_t row)
+{
+    return SetTextCursor(column * fontwidth(), row * fontheight());
+}
+
+
+int RA8875::columns(void)
+{
+    return width() / fontwidth();
+}
+
+
+int RA8875::rows(void)
+{
+    return height() / fontheight();
+}
+
+
+dim_t RA8875::width(void)
+{
+    return (ReadCommand(0x14) + 1) * 8;
+}
+
+
+dim_t RA8875::height(void)
+{
+    return (ReadCommand(0x19) | (ReadCommand(0x1A) << 8)) + 1;
+}
+
+
+dim_t RA8875::color_bpp(void)
+{
+    if ((ReadCommand(0x10) & 0x0C) == 0x04)
+        return 16;
+    else
+        return 8;
+}
+
+
+RetCode_t RA8875::SetTextCursor(loc_t x, loc_t y)
+{
+    cursor_x = x;     // set these values for non-internal fonts
+    cursor_y = y;
+    WriteCommandW(0x2A, x);
+    WriteCommandW(0x2C, y);
+    return noerror;
+}
+
+
+loc_t RA8875::GetTextCursor_Y(void)
+{
+    if (font == NULL)
+        return ReadCommand(0x2C) | (ReadCommand(0x2D) << 8);
+    else
+        return cursor_y;
+}
+
+
+loc_t RA8875::GetTextCursor_X(void)
+{
+    if (font == NULL)
+        return ReadCommand(0x2A) | (ReadCommand(0x2B) << 8);
+    else
+        return cursor_x;
+}
+
+
+RetCode_t RA8875::SetTextCursorControl(cursor_t cursor, bool blink)
+{
+    unsigned char mwcr0 = ReadCommand(0x40) & 0x0F; // retain direction, auto-increase
+    unsigned char mwcr1 = ReadCommand(0x41) & 0x01; // retain currently selected layer
+    unsigned char horz = 0;
+    unsigned char vert = 0;
+
+    mwcr0 |= 0x80;                  // text mode
+    if (cursor != NOCURSOR)
+        mwcr0 |= 0x40;              // visible
+    if (blink)
+        mwcr0 |= 0x20;              // blink
+    WriteCommand(0x40, mwcr0);      // configure the cursor
+    WriteCommand(0x41, mwcr1);      // close the graphics cursor
+    WriteCommand(0x44, 0x1f);       // The cursor flashing cycle
+    switch (cursor) {
+        case IBEAM:
+            horz = 0x01;
+            vert = 0x1F;
+            break;
+        case UNDER:
+            horz = 0x07;
+            vert = 0x01;
+            break;
+        case BLOCK:
+            horz = 0x07;
+            vert = 0x1F;
+            break;
+        case NOCURSOR:
+        default:
+            break;
+    }
+    WriteCommand(0x4e, horz);       // The cursor size horz
+    WriteCommand(0x4f, vert);       // The cursor size vert
+    return noerror;
+}
+
+
+RetCode_t RA8875::SetTextFont(RA8875::font_t font)
+{
+    if (/*font >= RA8875::ISO8859_1 && */ font <= RA8875::ISO8859_4) {
+        WriteCommand(0x21, (unsigned int)(font));
+        return noerror;
+    } else {
+        return bad_parameter;
+    }
+}
+
+
+RetCode_t RA8875::SetTextFontControl(fill_t fillit,
+                                     RA8875::font_angle_t angle,
+                                     RA8875::HorizontalScale hScale,
+                                     RA8875::VerticalScale vScale,
+                                     RA8875::alignment_t alignment)
+{
+    if (hScale >= 1 && hScale <= 4 &&
+            vScale >= 1 && vScale <= 4) {
+        unsigned char x = 0;
+
+        if (alignment == align_full)
+            x |= 0x80;
+        if (fillit == NOFILL)
+            x |= 0x40;
+        if (angle == rotated)
+            x |= 0x10;
+        x |= ((hScale - 1) << 2);
+        x |= ((vScale - 1) << 0);
+        WriteCommand(0x22, x);
+        return noerror;
+    } else {
+        return bad_parameter;
+    }
+}
+
+
+RetCode_t RA8875::SetTextFontSize(RA8875::HorizontalScale hScale, RA8875::VerticalScale vScale)
+{
+    unsigned char reg = ReadCommand(0x22);
+
+    if (vScale == -1)
+        vScale = hScale;
+    if (hScale >= 1 && hScale <= 4 && vScale >= 1 && vScale <= 4) {
+        reg &= 0xF0;    // keep the high nibble as is.
+        reg |= ((hScale - 1) << 2);
+        reg |= ((vScale - 1) << 0);
+        WriteCommand(0x22, reg);
+        return noerror;
+    } else {
+        return bad_parameter;
+    }
+}
+
+
+int RA8875::_putc(int c)
+{
+    if (font == NULL) {
+        return _internal_putc(c);
+    } else {
+        return _external_putc(c);
+    }
+}
+
+
+int RA8875::_external_putc(int c)
+{
+    if (c) {
+        if (c == '\r') {
+            cursor_x = 0;
+        } else if (c == '\n') {
+            cursor_y += font[2];
+        } else {
+            int advance = character(cursor_x, cursor_y, c);     // advance tells us how many pixels we advanced
+            //INFO("x,y,advance %d,%d,%d", cursor_x, cursor_y, advance);
+            if (advance) {
+                cursor_x += advance;
+                if (cursor_x >= width()) {
+                    cursor_x = 0;
+                    cursor_y += font[2];
+                    if (cursor_y >= height()) {
+                        cursor_y = 0;               // @todo Should it scroll?
+                    }
+                }
+            }
+        }
+    }
+    return c;
+}
+
+
+int RA8875::_internal_putc(int c)
+{
+    if (c) {
+        unsigned char mwcr0;
+
+        mwcr0 = ReadCommand(0x40);
+        if ((mwcr0 & 0x80) == 0x00) {
+            WriteCommand(0x40, 0x80 | mwcr0);    // Put in Text mode if not already
+        }
+        if (c == '\r') {
+            loc_t x;
+            x = ReadCommand(0x30) | (ReadCommand(0x31) << 8);   // Left edge of active window
+            WriteCommandW(0x2A, x);
+        } else if (c == '\n') {
+            loc_t y;
+            y = ReadCommand(0x2C) | (ReadCommand(0x2D) << 8);   // current y location
+            y += fontheight();
+            if (y >= height())               // @TODO after bottom of active window, then scroll window?
+                y = 0;
+            WriteCommandW(0x2C, y);
+        } else {
+            WriteCommand(0x02);                 // RA8875 Internal Fonts
+            _select(true);
+            WriteData(c);
+            _WaitWhileBusy(0x80);
+            _select(false);
+        }
+    }
+    return c;
+}
+
+
+RetCode_t RA8875::_StartGraphicsStream(void)
+{
+    WriteCommand(0x40,0x00);    // Graphics write mode
+    WriteCommand(0x02);         // Prepare for streaming data
+    return noerror;
+}
+
+
+RetCode_t RA8875::_EndGraphicsStream(void)
+{
+    return noerror;
+}
+
+
+RetCode_t RA8875::_putp(color_t pixel)
+{
+    WriteDataW((pixel>>8) | (pixel<<8));
+    return noerror;
+}
+
+
+void RA8875::puts(loc_t x, loc_t y, const char * string)
+{
+    SetTextCursor(x,y);
+    puts(string);
+}
+
+
+void RA8875::puts(const char * string)
+{
+    unsigned char mwcr0 = ReadCommand(0x40);
+
+    if (font == NULL) {
+        if ((mwcr0 & 0x80) == 0x00)
+            WriteCommand(0x40,0x80);    // Put in Text mode if not already
+    } else {
+        _StartGraphicsStream();
+    }
+    if (*string != '\0') {
+#if 1
+        while (*string) {           // @TODO calling individual _putc is slower... optimizations?
+            _putc(*string++);
+        }
+#else
+        WriteCommand(0x02);
+        _select(true);
+        while (*string != '\0') {
+            WriteData(*string);
+            ++string;
+            _WaitWhileBusy(0x80);
+        }
+        _select(false);
+#endif
+    }
+    if (font)
+        _EndGraphicsStream();
+}
+
+
+RetCode_t RA8875::SetGraphicsCursor(loc_t x, loc_t y)
+{
+    WriteCommandW(0x46, x);
+    WriteCommandW(0x48, y);
+    return noerror;
+}
+
+
+RetCode_t RA8875::SetGraphicsCursorRead(loc_t x, loc_t y)
+{
+    //WriteCommand(0x40, 0);  // Graphics mode
+    //WriteCommand(0x45, 0);  // left->right, top->bottom
+    WriteCommandW(0x4A, x);
+    WriteCommandW(0x4C, y);
+    return noerror;
+}
+
+
+RetCode_t RA8875::window(loc_t x, loc_t y, dim_t width, dim_t height)
+{
+    GraphicsDisplay::window(x,y, width,height);
+    WriteCommandW(0x30, x);
+    WriteCommandW(0x32, y);
+    WriteCommandW(0x34, (x+width-1));
+    WriteCommandW(0x36, (y+height-1));
+    SetGraphicsCursor(x,y);
+    return noerror;
+}
+
+
+RetCode_t RA8875::cls(uint16_t layers)
+{
+    RetCode_t ret;
+
+    PERFORMANCE_RESET;
+    if (layers == 0) {
+        ret = clsw(FULLWINDOW);
+        ret = SetTextCursor(0,0);
+    } else if (layers > 3) {
+        ret = bad_parameter;
+    } else {
+        uint16_t prevLayer = GetDrawingLayer();
+        if (layers & 1) {
+            SelectDrawingLayer(0);
+            clsw(FULLWINDOW);
+        }
+        if (layers & 2) {
+            SelectDrawingLayer(1);
+            clsw(FULLWINDOW);
+        }
+        ret = SelectDrawingLayer(prevLayer);
+    }
+    REGISTERPERFORMANCE(PRF_CLS);
+    return ret;
+}
+
+
+RetCode_t RA8875::clsw(RA8875::Region_t region)
+{
+    PERFORMANCE_RESET;
+    WriteCommand(0x8E, (region == ACTIVEWINDOW) ? 0xC0 : 0x80);
+    _WaitWhileReg(0x8E, 0x80);
+    REGISTERPERFORMANCE(PRF_CLS);
+    return noerror;
+}
+
+
+RetCode_t RA8875::pixel(loc_t x, loc_t y, color_t color)
+{
+    RetCode_t ret;
+
+    PERFORMANCE_RESET;
+#if 1
+    ret = pixelStream(&color, 1, x,y);
+#else
+    foreground(color);
+    ret = pixel(x,y);
+#endif
+    REGISTERPERFORMANCE(PRF_DRAWPIXEL);
+    return ret;
+}
+
+
+RetCode_t RA8875::pixel(loc_t x, loc_t y)
+{
+    RetCode_t ret;
+
+    PERFORMANCE_RESET;
+    color_t color = GetForeColor();
+#if 1
+    ret = pixelStream(&color, 1, x, y);
+#else
+    WriteCommand(0x40,0x00);    // Graphics write mode
+    SetGraphicsCursor(x, y);
+    WriteCommand(0x02);
+    WriteDataW(color);
+    ret = noerror;
+#endif
+    REGISTERPERFORMANCE(PRF_DRAWPIXEL);
+    return ret;
+}
+
+
+RetCode_t RA8875::pixelStream(color_t * p, uint32_t count, loc_t x, loc_t y)
+{
+    PERFORMANCE_RESET;
+    WriteCommand(0x40,0x00);    // Graphics write mode
+    SetGraphicsCursor(x, y);
+    WriteCommand(0x02);
+    _select(true);
+    _spiwrite(0x00);         // Cmd: write data
+    while (count--) {
+        _spiwrite(*p >> 8);
+        _spiwrite(*p & 0xFF);
+        p++;
+    }
+    _select(false);
+    REGISTERPERFORMANCE(PRF_PIXELSTREAM);
+    return(noerror);
+}
+
+
+color_t RA8875::getPixel(loc_t x, loc_t y)
+{
+    color_t pixel;
+
+    PERFORMANCE_RESET;
+    //WriteCommand(0x45,0x00);    // read left->right, top->bottom
+    WriteCommand(0x40,0x00);    // Graphics write mode
+    SetGraphicsCursorRead(x, y);
+    WriteCommand(0x02);
+    _select(true);
+    _spiwrite(0x40);         // Cmd: read data
+    _spiwrite(0x00);         // dummy read
+    pixel  = _spiread();
+    pixel |= (_spiread() << 8);
+    _select(false);
+    REGISTERPERFORMANCE(PRF_READPIXEL);
+    return pixel;
+}
+
+
+RetCode_t RA8875::getPixelStream(color_t * p, uint32_t count, loc_t x, loc_t y)
+{
+    color_t pixel;
+
+    PERFORMANCE_RESET;
+    //WriteCommand(0x45,0x00);    // read left->right, top->bottom
+    WriteCommand(0x40,0x00);    // Graphics write mode
+    SetGraphicsCursorRead(x, y);
+    WriteCommand(0x02);
+    _select(true);
+    _spiwrite(0x40);         // Cmd: read data
+    _spiwrite(0x00);         // dummy read
+    while (count--) {
+        pixel  = _spiread();
+        pixel |= (_spiread() << 8);
+        *p++ = pixel;
+    }
+    _select(false);
+    REGISTERPERFORMANCE(PRF_READPIXELSTREAM);
+    return noerror;
+}
+
+
+RetCode_t RA8875::line(loc_t x1, loc_t y1, loc_t x2, loc_t y2, color_t color)
+{
+    foreground(color);
+    return line(x1,y1,x2,y2);
+}
+
+
+RetCode_t RA8875::line(loc_t x1, loc_t y1, loc_t x2, loc_t y2)
+{
+    PERFORMANCE_RESET;
+    if (x1 == x2 && y1 == y2) {
+        pixel(x1, y1);
+    } else {
+        WriteCommandW(0x91, x1);
+        WriteCommandW(0x93, y1);
+        WriteCommandW(0x95, x2);
+        WriteCommandW(0x97, y2);
+        unsigned char drawCmd = 0x00;       // Line
+        WriteCommand(0x90, drawCmd);
+        WriteCommand(0x90, 0x80 + drawCmd); // Start drawing.
+        _WaitWhileReg(0x90, 0x80);
+    }
+    REGISTERPERFORMANCE(PRF_DRAWLINE);
+    return noerror;
+}
+
+RetCode_t RA8875::fillrect(rect_t r, color_t color, fill_t fillit)
+{
+    return rect(r.p1.x, r.p1.y, r.p2.x, r.p2.y, color, fillit);
+}
+
+RetCode_t RA8875::fillrect(loc_t x1, loc_t y1, loc_t x2, loc_t y2,
+                           color_t color, fill_t fillit)
+{
+    return rect(x1,y1,x2,y2,color,fillit);
+}
+
+RetCode_t RA8875::rect(rect_t r, color_t color, fill_t fillit)
+{
+    return rect(r.p1.x, r.p1.y, r.p2.x, r.p2.y, color, fillit);
+}
+
+RetCode_t RA8875::rect(loc_t x1, loc_t y1, loc_t x2, loc_t y2,
+                       color_t color, fill_t fillit)
+{
+    foreground(color);
+    return rect(x1,y1,x2,y2,fillit);
+}
+
+
+RetCode_t RA8875::rect(loc_t x1, loc_t y1, loc_t x2, loc_t y2,
+                       fill_t fillit)
+{
+    PERFORMANCE_RESET;
+    if (x1 == x2 && y1 == y2) {
+        pixel(x1, y1);
+    } else if (x1 == x2) {
+        line(x1, y1, x2, y2);
+    } else if (y1 == y2) {
+        line(x1, y1, x2, y2);
+    } else {
+        WriteCommandW(0x91, x1);
+        WriteCommandW(0x93, y1);
+        WriteCommandW(0x95, x2);
+        WriteCommandW(0x97, y2);
+        unsigned char drawCmd = 0x10;   // Rectangle
+        if (fillit == FILL)
+            drawCmd |= 0x20;
+        WriteCommand(0x90, drawCmd);
+        WriteCommand(0x90, 0x80 + drawCmd); // Start drawing.
+        _WaitWhileReg(0x90, 0x80);
+    }
+    REGISTERPERFORMANCE(PRF_DRAWRECTANGLE);
+    return noerror;
+}
+
+
+RetCode_t RA8875::fillroundrect(loc_t x1, loc_t y1, loc_t x2, loc_t y2,
+                                dim_t radius1, dim_t radius2, color_t color, fill_t fillit)
+{
+    foreground(color);
+    return roundrect(x1,y1,x2,y2,radius1,radius2,fillit);
+}
+
+
+RetCode_t RA8875::roundrect(loc_t x1, loc_t y1, loc_t x2, loc_t y2,
+                            dim_t radius1, dim_t radius2, color_t color, fill_t fillit)
+{
+    foreground(color);
+    return roundrect(x1,y1,x2,y2,radius1,radius2,fillit);
+}
+
+
+RetCode_t RA8875::roundrect(loc_t x1, loc_t y1, loc_t x2, loc_t y2,
+                            dim_t radius1, dim_t radius2, fill_t fillit)
+{
+    RetCode_t ret = noerror;
+
+    PERFORMANCE_RESET;
+    if (x1 > x2 || y1 > y2 || (radius1 > (x2-x1)/2) || (radius2 > (y2-y1)/2) ) {
+        ret = bad_parameter;
+    } else if (x1 == x2 && y1 == y2) {
+        pixel(x1, y1);
+    } else if (x1 == x2) {
+        line(x1, y1, x2, y2);
+    } else if (y1 == y2) {
+        line(x1, y1, x2, y2);
+    } else {
+        WriteCommandW(0x91, x1);
+        WriteCommandW(0x93, y1);
+        WriteCommandW(0x95, x2);
+        WriteCommandW(0x97, y2);
+        WriteCommandW(0xA1, radius1);
+        WriteCommandW(0xA3, radius2);
+        // Should not need this...
+        WriteCommandW(0xA5, 0);
+        WriteCommandW(0xA7, 0);
+        unsigned char drawCmd = 0x20;       // Rounded Rectangle
+        if (fillit == FILL)
+            drawCmd |= 0x40;
+        WriteCommand(0xA0, drawCmd);
+        WriteCommand(0xA0, 0x80 + drawCmd); // Start drawing.
+        _WaitWhileReg(0xA0, 0x80);
+    }
+    REGISTERPERFORMANCE(PRF_DRAWROUNDEDRECTANGLE);
+    return ret;
+}
+
+
+RetCode_t RA8875::triangle(loc_t x1, loc_t y1, loc_t x2, loc_t y2,
+                           loc_t x3, loc_t y3, color_t color, fill_t fillit)
+{
+    RetCode_t ret;
+
+    foreground(color);
+    ret = triangle(x1,y1,x2,y2,x3,y3,fillit);
+    return ret;
+}
+
+
+RetCode_t RA8875::filltriangle(loc_t x1, loc_t y1, loc_t x2, loc_t y2,
+                               loc_t x3, loc_t y3, color_t color, fill_t fillit)
+{
+    RetCode_t ret;
+
+    foreground(color);
+    ret = triangle(x1,y1,x2,y2,x3,y3,fillit);
+    return ret;
+}
+
+
+RetCode_t RA8875::triangle(loc_t x1, loc_t y1 ,loc_t x2, loc_t y2,
+                           loc_t x3, loc_t y3, fill_t fillit)
+{
+    RetCode_t ret = noerror;
+
+    PERFORMANCE_RESET;
+    if (x1 == x2 && y1 == y2 && x1 == x3 && y1 == y3) {
+        pixel(x1, y1);
+    } else {
+        WriteCommandW(0x91, x1);
+        WriteCommandW(0x93, y1);
+        WriteCommandW(0x95, x2);
+        WriteCommandW(0x97, y2);
+        WriteCommandW(0xA9, x3);
+        WriteCommandW(0xAB, y3);
+        unsigned char drawCmd = 0x01;       // Triangle
+        if (fillit == FILL)
+            drawCmd |= 0x20;
+        WriteCommand(0x90, drawCmd);
+        WriteCommand(0x90, 0x80 + drawCmd); // Start drawing.
+        _WaitWhileReg(0x90, 0x80);
+    }
+    REGISTERPERFORMANCE(PRF_DRAWTRIANGLE);
+    return ret;
+}
+
+RetCode_t RA8875::circle(loc_t x, loc_t y, dim_t radius,
+                         color_t color, fill_t fillit)
+{
+    foreground(color);
+    return circle(x,y,radius,fillit);
+}
+
+
+RetCode_t RA8875::fillcircle(loc_t x, loc_t y, dim_t radius,
+                             color_t color, fill_t fillit)
+{
+    foreground(color);
+    return circle(x,y,radius,fillit);
+}
+
+
+RetCode_t RA8875::circle(loc_t x, loc_t y, dim_t radius, fill_t fillit)
+{
+    RetCode_t ret = noerror;
+
+    PERFORMANCE_RESET;
+    if (radius <= 0) {
+        ret = bad_parameter;
+    } else if (radius == 1) {
+        pixel(x,y);
+    } else {
+        WriteCommandW(0x99, x);
+        WriteCommandW(0x9B, y);
+        WriteCommand(0x9d, radius & 0xFF);
+        unsigned char drawCmd = 0x00;       // Circle
+        if (fillit == FILL)
+            drawCmd |= 0x20;
+        WriteCommand(0x90, drawCmd);
+        WriteCommand(0x90, 0x40 + drawCmd); // Start drawing.
+        _WaitWhileReg(0x90, 0x40);
+    }
+    REGISTERPERFORMANCE(PRF_DRAWCIRCLE);
+    return ret;
+}
+
+
+RetCode_t RA8875::ellipse(loc_t x, loc_t y, dim_t radius1, dim_t radius2, color_t color, fill_t fillit)
+{
+    foreground(color);
+    return ellipse(x,y,radius1,radius2,fillit);
+}
+
+
+RetCode_t RA8875::fillellipse(loc_t x, loc_t y, dim_t radius1, dim_t radius2, color_t color, fill_t fillit)
+{
+    foreground(color);
+    return ellipse(x,y,radius1,radius2,fillit);
+}
+
+
+RetCode_t RA8875::ellipse(loc_t x, loc_t y, dim_t radius1, dim_t radius2, fill_t fillit)
+{
+    RetCode_t ret = noerror;
+
+    PERFORMANCE_RESET;
+    if (radius1 <= 0 || radius2 <= 0) {
+        ;   // do nothing
+    } else if (radius1 == 1 && radius2 == 1) {
+        pixel(x, y);
+    } else {
+        WriteCommandW(0xA5, x);
+        WriteCommandW(0xA7, y);
+        WriteCommandW(0xA1, radius1);
+        WriteCommandW(0xA3, radius2);
+        unsigned char drawCmd = 0x00;   // Ellipse
+        if (fillit == FILL)
+            drawCmd |= 0x40;
+        WriteCommand(0xA0, drawCmd);
+        WriteCommand(0xA0, 0x80 + drawCmd); // Start drawing.
+        _WaitWhileReg(0xA0, 0x80);
+    }
+    REGISTERPERFORMANCE(PRF_DRAWELLIPSE);
+    return ret;
+}
+
+
+RetCode_t RA8875::frequency(unsigned long Hz, unsigned long Hz2)
+{
+    spiwritefreq = Hz;
+    if (Hz2 != 0)
+        spireadfreq = Hz2;
+    else
+        spireadfreq = Hz/2;
+    _setWriteSpeed(true);
+    //       __   ___
+    // Clock   ___A     Rising edge latched
+    //       ___ ____
+    // Data  ___X____
+    spi.format(8, 3);           // 8 bits and clock to data phase 0
+    return noerror;
+}
+
+void RA8875::_setWriteSpeed(bool writeSpeed)
+{
+    if (writeSpeed) {
+        spi.frequency(spiwritefreq);
+        spiWriteSpeed = true;
+    } else {
+        spi.frequency(spireadfreq);
+        spiWriteSpeed = false;
+    }
+}
+
+RetCode_t RA8875::Power(bool on)
+{
+    WriteCommand(0x01, (on) ? 0x80 : 0x00);
+    return noerror;
+}
+
+
+RetCode_t RA8875::Backlight_u8(unsigned char brightness)
+{
+    static bool is_enabled = false;
+    if (brightness == 0) {
+        WriteCommand(0x8a); // Disable the PWM
+        WriteData(0x00);
+        is_enabled = false;
+    } else if (!is_enabled) {
+        WriteCommand(0x8a); // Enable the PWM
+        WriteData(0x80);
+        WriteCommand(0x8a); // Not sure why this is needed, but following the pattern
+        WriteData(0x81);    // open PWM (SYS_CLK / 2 as best I can tell)
+        is_enabled = true;
+    }
+    WriteCommand(0x8b, brightness);  // Brightness parameter 0xff-0x00
+    return noerror;
+}
+
+
+RetCode_t RA8875::Backlight(float brightness)
+{
+    unsigned char b;
+
+    if (brightness >= 1.0)
+        b = 255;
+    else if (brightness <= 0.0)
+        b = 0;
+    else
+        b = (unsigned char)(brightness * 255);
+    return Backlight_u8(b);
+}
+
+
+RetCode_t RA8875::set_font(const unsigned char * _font)
+{
+    if (font && ! _font) {
+        SetTextCursor(cursor_x, cursor_y);  // soft-font cursor -> hw cursor
+    }
+    font = _font;
+    GraphicsDisplay::set_font(_font);
+    return noerror;     // trusting them, but it might be good to put some checks in here...
+}
+
+
+RetCode_t RA8875::background(color_t color)
+{
+    GraphicsDisplay::background(color);
+    WriteCommand(0x60, (color>>11));                  // BGCR0
+    WriteCommand(0x61, (unsigned char)(color>>5));    // BGCR0
+    WriteCommand(0x62, (unsigned char)(color));       // BGCR0
+    return noerror;
+}
+
+
+RetCode_t RA8875::background(unsigned char r, unsigned char g, unsigned char b)
+{
+    background(RGB(r,g,b));
+//    WriteCommand(0x60, r);
+//    WriteCommand(0x61, g);
+//    WriteCommand(0x62, b);
+    return noerror;
+}
+
+
+RetCode_t RA8875::foreground(color_t color)
+{
+    GraphicsDisplay::foreground(color);
+    WriteCommand(0x63, (unsigned char)(color>>11));
+    WriteCommand(0x64, (unsigned char)(color>>5));
+    WriteCommand(0x65, (unsigned char)(color));
+    return noerror;
+}
+
+
+RetCode_t RA8875::foreground(unsigned char r, unsigned char g, unsigned char b)
+{
+    foreground(RGB(r,g,b));
+//    WriteCommand(0x63, r);
+//    WriteCommand(0x64, g);
+//    WriteCommand(0x65, b);
+    return noerror;
+}
+
+
+color_t RA8875::GetForeColor(void)
+{
+    color_t color;
+
+    color  = (ReadCommand(0x63) & 0x1F) << 11;
+    color |= (ReadCommand(0x64) & 0x3F) << 5;
+    color |= (ReadCommand(0x65) & 0x1F);
+    return color;
+}
+
+
+color_t RA8875::DOSColor(int i)
+{
+    const color_t colors[16] = {
+        Black,    Blue,       Green,       Cyan,
+        Red,      Magenta,    Brown,       Gray,
+        Charcoal, BrightBlue, BrightGreen, BrightCyan,
+        Orange,   Pink,       Yellow,      White
+    };
+    if (i < 16)
+        return colors[i];
+    else
+        return 0;
+}
+
+
+const char * RA8875::DOSColorNames(int i)
+{
+    const char * names[16] = {
+        "Black",    "Blue",       "Green",       "Cyan",
+        "Red",      "Magenta",    "Brown",       "Gray",
+        "Charcoal", "BrightBlue", "BrightGreen", "BrightCyan",
+        "Orange",   "Pink",       "Yellow",      "White"
+    };
+    if (i < 16)
+        return names[i];
+    else
+        return NULL;
+}
+
+
+///////////////////////////////////////////////////////////////
+// Private functions
+
+unsigned char RA8875::_spiwrite(unsigned char data)
+{
+    unsigned char retval;
+
+    if (!spiWriteSpeed)
+        _setWriteSpeed(true);
+    retval = spi.write(data);
+    return retval;
+}
+
+
+unsigned char RA8875::_spiread(void)
+{
+    unsigned char retval;
+    unsigned char data = 0;
+
+    if (spiWriteSpeed)
+        _setWriteSpeed(false);
+    retval = spi.write(data);
+    return retval;
+}
+
+
+RetCode_t RA8875::_select(bool chipsel)
+{
+    cs = (chipsel == true) ? 0 : 1;
+    return noerror;
+}
+
+
+RetCode_t RA8875::PrintScreen(uint16_t layer, loc_t x, loc_t y, dim_t w, dim_t h, const char *Name_BMP)
+{
+#if 1
+    (void)layer;
+    return PrintScreen(x, y, w, h, Name_BMP);
+#else
+    // This is the deprecated interface and with the changes it is no longer implemented correctly.
+    uint16_t curLayer = GetDrawingLayer();
+    RetCode_t ret = SelectDrawingLayer(layer);
+    if (ret == noerror) {
+        ret = PrintScreen(x, y, w, h, Name_BMP);
+    }
+    SelectDrawingLayer(curLayer);
+    return ret;
+#endif
+}
+
+
+RetCode_t RA8875::PrintScreen(loc_t x, loc_t y, dim_t w, dim_t h, const char *Name_BMP)
+{
+    BITMAPFILEHEADER BMP_Header;
+    BITMAPINFOHEADER BMP_Info;
+
+    INFO("(%d,%d) - (%d,%d) %s", x,y,w,h,Name_BMP);
+    if (x >= 0 && x < width()
+            && y >= 0 && y < height()
+            && w > 0 && x + w <= width()
+            && h > 0 && y + h <= height()) {
+
+        BMP_Header.bfType = BF_TYPE;
+        BMP_Header.bfSize = (w * h * sizeof(RGBQUAD)) + sizeof(BMP_Header) + sizeof(BMP_Header);
+        BMP_Header.bfReserved1 = 0;
+        BMP_Header.bfReserved2 = 0;
+        BMP_Header.bfOffBits = sizeof(BMP_Header) + sizeof(BMP_Header);
+
+        BMP_Info.biSize = sizeof(BMP_Info);
+        BMP_Info.biWidth = w;
+        BMP_Info.biHeight = h;
+        BMP_Info.biPlanes = 1;
+        BMP_Info.biBitCount = 24;
+        BMP_Info.biCompression = BI_RGB;
+        BMP_Info.biSizeImage = 0;
+        BMP_Info.biXPelsPerMeter = 0;
+        BMP_Info.biYPelsPerMeter = 0;
+        BMP_Info.biClrUsed = 0;
+        BMP_Info.biClrImportant = 0;
+
+        INFO("Writing {%s}", Name_BMP);
+        FILE *Image = fopen(Name_BMP, "wb");
+        if (!Image) {
+            ERR("File not found");
+            return(file_not_found);
+        }
+
+        // Be optimistic - don't check for errors.
+        //HexDump("BMP_Header", (uint8_t *)&BMP_Header, sizeof(BMP_Header));
+        fwrite(&BMP_Header, sizeof(char), sizeof(BMP_Header), Image);
+        //INFO("fwrite returned %d", r);
+
+        //HexDump("BMP_Info", (uint8_t *)&BMP_Info, sizeof(BMP_Info));
+        fwrite(&BMP_Info, sizeof(char), sizeof(BMP_Info), Image);
+        //INFO("fwrite returned %d", r);
+
+        int lineBufSize = ((24 * w + 7)/8);
+        uint8_t * lineBuffer = (uint8_t *)malloc(lineBufSize);
+        if (lineBuffer == NULL) {
+            fclose(Image);
+            ERR("Not enough RAM for lineBuffer");
+            return(not_enough_ram);
+        }
+        color_t * pixelBuffer = (color_t *)malloc(w * sizeof(color_t));
+        color_t * pixelBuffer2 = (color_t *)malloc(w * sizeof(color_t));
+        color_t transparency = GetBackgroundTransparencyColor();
+        unsigned char ltpr0 = ReadCommand(0x52) & 0x7;
+
+        if (pixelBuffer == NULL || pixelBuffer2 == NULL) {
+            fclose(Image);
+            free(lineBuffer);
+            ERR("Not enough RAM for pixelBuffer");
+            if (pixelBuffer)
+                free(pixelBuffer);
+            return(not_enough_ram);
+        }
+
+        uint16_t prevLayer = GetDrawingLayer();
+        // If only one of the layers is visible, select that layer
+        switch(ltpr0) {
+            case 0:
+                SelectDrawingLayer(0);
+                break;
+            case 1:
+                SelectDrawingLayer(1);
+                break;
+            default:
+                break;
+        }
+
+        // Read the display from the last line toward the top
+        // so we can write the file in one pass.
+        for (int j = h - 1; j >= 0; j--) {
+            if (ltpr0 >= 2)             // Need to combine the layers...
+                SelectDrawingLayer(0);  // so read layer 0 first
+            // Read one line of pixels to a local buffer
+            if (getPixelStream(pixelBuffer, w, x,y+j) != noerror) {
+                ERR("getPixelStream error, and no recovery handler...");
+            }
+            if (ltpr0 >= 2) {           // Need to combine the layers...
+                SelectDrawingLayer(1);  // so read layer 0 first
+                if (getPixelStream(pixelBuffer2, w, x,y+j) != noerror) {
+                    ERR("getPixelStream error, and no recovery handler...");
+                }
+            }
+            // Convert the local buffer to RGBQUAD format
+            int lb = 0;
+            for (int i=0; i<w; i++) {
+                RGBQUAD q0 = RGB16ToRGBQuad(pixelBuffer[x+i]);      // Scale to 24-bits
+                RGBQUAD q1 = RGB16ToRGBQuad(pixelBuffer2[x+i]);     // Scale to 24-bits
+                switch (ltpr0) {
+                    case 0:
+                    case 1:
+                    case 2: // lighten-overlay  (@TODO Not supported yet)
+                    case 6: // Floating Windows     (@TODO not sure how to support)
+                    default: // Reserved...
+                        lineBuffer[lb++] = q0.rgbBlue;
+                        lineBuffer[lb++] = q0.rgbGreen;
+                        lineBuffer[lb++] = q0.rgbRed;
+                        break;
+                    case 3: // transparent mode (@TODO Read the background color register for transparent)
+                    case 4: // boolean or
+                        lineBuffer[lb++] = q0.rgbBlue | q1.rgbBlue;
+                        lineBuffer[lb++] = q0.rgbGreen | q1.rgbGreen;
+                        lineBuffer[lb++] = q0.rgbRed | q1.rgbRed;
+                        break;
+                    case 5: // boolean AND
+                        lineBuffer[lb++] = q0.rgbBlue & q1.rgbBlue;
+                        lineBuffer[lb++] = q0.rgbGreen & q1.rgbGreen;
+                        lineBuffer[lb++] = q0.rgbRed & q1.rgbRed;
+                        break;
+                }
+            }
+            if (j == h - 1)
+                HexDump("Line", lineBuffer, lineBufSize);
+            // Write to disk
+            fwrite(lineBuffer, sizeof(char), lb, Image);
+        }
+        SelectDrawingLayer(prevLayer);
+        fclose(Image);
+        free(pixelBuffer2);  // don't leak memory.
+        free(pixelBuffer);
+        free(lineBuffer);
+        INFO("Image closed");
+        return noerror;
+    } else {
+        return bad_parameter;
+    }
+}
+
+
+// ##########################################################################
+// ##########################################################################
+// ##########################################################################
+
+#ifdef TESTENABLE
+
+#include "Arial12x12.h"
+#include "Small_6.h"
+
+//      ______________  ______________  ______________  _______________
+//     /_____   _____/ /  ___________/ /  ___________/ /_____   ______/
+//          /  /      /  /            /  /                  /  /
+//         /  /      /  /___         /  /__________        /  /
+//        /  /      /  ____/        /__________   /       /  /
+//       /  /      /  /                       /  /       /  /
+//      /  /      /  /__________  ___________/  /       /  /
+//     /__/      /_____________/ /_____________/       /__/
+//
+//    Everything from here down is test code.
+//
+bool SuppressSlowStuff = false;
+
+void TextWrapTest(RA8875 & display, Serial & pc)
+{
+    if (!SuppressSlowStuff)
+        pc.printf("Text Wrap Test\r\n");
+    display.background(Black);
+    display.foreground(Blue);
+    display.cls();
+    display.Backlight_u8(255);
+    display.puts(0,0, "Text Wrap Test.\r\n");
+    for (int i=1; i<60; i++) {
+        display.printf("L%2d\n", i % 17);
+        if (!SuppressSlowStuff)
+            wait_ms(100);
+    }
+    if (!SuppressSlowStuff)
+        wait_ms(3000);
+}
+
+
+void ShowKey(RA8875 & display, int key)
+{
+    loc_t col, row;
+    dim_t r1 = 25;
+    color_t color = (key & 0x80) ? Red : Green;
+
+    key &= 0x7F;        // remove the long-press flag
+    row = (key - 1) / 5;
+    col = (key - 1) % 5;
+    if (col > 5) col = 5;
+    if (row > 4) row = 4;
+    display.circle(450 - + (2 * r1) * col, 200 - (2 * r1) * row, r1-2, color, FILL);
+}
+
+void HideKey(RA8875 & display, int key)
+{
+    loc_t col, row;
+    dim_t r1 = 25;
+
+    row = (key - 1) / 5;
+    col = (key - 1) % 5;
+    if (col > 5) col = 5;
+    if (row > 4) row = 4;
+    display.background(Black);
+    display.circle(450 - (2 * r1) * col, 200 - (2 * r1) * row, r1-2, Black, FILL);
+    display.circle(450 - (2 * r1) * col, 200 - (2 * r1) * row, r1-2, Blue);
+}
+
+void KeyPadTest(RA8875 & display, Serial & pc)
+{
+    const uint8_t myMap[22] = {
+        0,
+        'a', 'b', 'c', 'd', 'e',
+        'f', 'g', 'h', 'i', 'j',
+        'k', 'l', 'm', 'n', 'o',
+        'p', 'q', 'r', 's', 't',
+        'x'
+    };
+
+    display.background(Black);
+    display.foreground(Blue);
+    display.cls();
+    display.Backlight_u8(255);
+    display.puts(0,0, "KeyPad Test. Touch the keypad...");
+    pc.printf("\r\n"
+              "Raw KeyPad Test. Keypad returns the key-number.\r\n"
+              "Press [most] any PC keyboard key to advance to next test.\r\n");
+    RetCode_t ret = display.KeypadInit(true, true, 3, 7, 3);
+    if (ret != noerror)
+        pc.printf("returncode from KeypadInit is %d\r\n", ret);
+    int lastKey = 0;
+    while (!pc.readable()) {
+        if (display.readable()) {
+            int key = display.getc();
+            if (key) {
+                if (((key & 0x7F) != lastKey) && (lastKey != 0))
+                    HideKey(display, lastKey);
+                ShowKey(display, key);
+                lastKey = key & 0x7F;
+            } else {
+                // erase the last one
+                if (lastKey)
+                    HideKey(display, lastKey);
+            }
+        }
+    }
+    (void)pc.getc();
+    pc.printf("\r\n"
+              "Map KeyPad Test. Keypad returns the remapped key 'a' - 't'.\r\n"
+              "Press [most] any PC keyboard key to advance to exit test.\r\n");
+    display.SetKeyMap(myMap);
+    while (!pc.readable()) {
+        if (display.readable()) {
+            int key = display.getc();
+            bool longPress = key & 0x80;
+            display.SetTextCursor(0, 120);
+            display.printf("Long Press: %d\r\n", longPress);
+            display.printf("  Remapped: %c %02X\r\n", (key) ? key & 0x7F : ' ', key);
+        }
+    }
+    (void)pc.getc();
+    display.SetKeyMap();
+    pc.printf("\r\n");
+}
+
+void TextCursorTest(RA8875 & display, Serial & pc)
+{
+    const char * iCursor  = "The I-Beam cursor should be visible for this text.\r\n";
+    const char * uCursor  = "The Underscore cursor should be visible for this text.\r\n";
+    const char * bCursor  = "The Block cursor should be visible for this text.\r\n";
+    const char * bbCursor = "The Blinking Block cursor should be visible for this text.\r\n";
+    const char * p;
+    int delay = 100;
+
+    if (!SuppressSlowStuff)
+        pc.printf("Text Cursor Test\r\n");
+    else
+        delay = 0;
+    display.background(Black);
+    display.foreground(Blue);
+    display.cls();
+    display.Backlight_u8(255);
+    display.puts(0,0, "Text Cursor Test.");
+
+    // visible, non-blinking
+    display.SetTextCursor(0,20);
+    display.SetTextCursorControl(RA8875::IBEAM, false);
+    p = iCursor;
+    while (*p) {
+        display._putc(*p++);
+        wait_ms(delay);
+    }
+
+    display.SetTextCursorControl(RA8875::UNDER, false);
+    p = uCursor;
+    while (*p) {
+        display._putc(*p++);
+        wait_ms(delay);
+    }
+
+    display.SetTextCursorControl(RA8875::BLOCK, false);
+    p = bCursor;
+    while (*p) {
+        display._putc(*p++);
+        wait_ms(delay);
+    }
+
+    display.SetTextCursorControl(RA8875::BLOCK, true);
+    p = bbCursor;
+    while (*p) {
+        display._putc(*p++);
+        wait_ms(delay);
+    }
+    wait_ms(delay * 20);
+    display.SetTextCursorControl(RA8875::NOCURSOR, false);
+}
+
+
+void BacklightTest(RA8875 & display, Serial & pc, float ramptime)
+{
+    char buf[60];
+    unsigned int w = (ramptime * 1000)/ 256;
+    int delay = 200;
+
+    if (!SuppressSlowStuff)
+        pc.printf("Backlight Test - ramp over %f sec.\r\n", ramptime);
+    else {
+        delay = 0;
+        w = 0;
+    }
+    display.Backlight_u8(0);
+    display.background(White);
+    display.foreground(Blue);
+    display.cls();
+    wait_ms(delay);
+    display.puts(0,0, "RA8875 Backlight Test - Ramp up.");
+    for (int i=0; i <= 255; i++) {
+        sprintf(buf, "%3d, %4d", i, w);
+        display.puts(100,100,buf);
+        display.Backlight_u8(i);
+        wait_ms(w);
+    }
+}
+
+
+void BacklightTest2(RA8875 & display, Serial & pc)
+{
+    int delay = 20;
+
+    if (!SuppressSlowStuff)
+        pc.printf("Backlight Test 2\r\n");
+    else
+        delay = 0;
+
+    // Dim it out at the end of the tests.
+    display.foreground(Blue);
+    display.puts(0,0, "Ramp Backlight down.");
+    // Ramp it off
+    for (int i=255; i != 0; i--) {
+        display.Backlight_u8(i);
+        wait_ms(delay);
+    }
+    display.Backlight_u8(0);
+}
+
+
+void ExternalFontTest(RA8875 & display, Serial & pc)
+{
+    if (!SuppressSlowStuff)
+        pc.printf("External Font Test\r\n");
+    display.background(Black);
+    display.foreground(Blue);
+    display.cls();
+    display.Backlight(1);
+    display.puts(0,0, "External Font Test.");
+
+    display.set_font(Small_6);
+    display.puts(0,30, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\r\n");
+
+    display.set_font(Arial12x12);
+    display.puts("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\r\n");
+    display.set_font();     // restore to internal
+
+    display.puts("Normal font again.");
+    //display.window(0,0, display.width(), display.height());
+}
+
+
+void DOSColorTest(RA8875 & display, Serial & pc)
+{
+    if (!SuppressSlowStuff)
+        pc.printf("DOS Color Test\r\n");
+    display.background(Black);
+    display.foreground(Blue);
+    display.cls();
+    display.puts(0,0, "DOS Colors - Fore");
+    display.puts(280,0, "Back");
+    display.background(Gray);
+    for (int i=0; i<16; i++) {
+        display.foreground(display.DOSColor(i));
+        display.puts(160, i*16, display.DOSColorNames(i));
+        display.background(Black);
+    }
+    display.foreground(White);
+    for (int i=0; i<16; i++) {
+        display.background(display.DOSColor(i));
+        display.puts(360, i*16, display.DOSColorNames(i));
+        display.foreground(White);
+    }
+}
+
+
+void WebColorTest(RA8875 & display, Serial & pc)
+{
+    if (!SuppressSlowStuff)
+        pc.printf("Web Color Test\r\n");
+    display.background(Black);
+    display.foreground(Blue);
+    display.window(0,0, display.width(), display.height());
+    display.cls();
+    display.SetTextFontSize(1,1);
+    display.puts(200,0, "Web Color Test");
+    display.SetTextCursor(0,0);
+    display.puts("  ");
+    for (int i=0; i<16; i++)
+        display.printf("%X", i&0xF);
+    display.puts("\r\n0 ");
+    for (int i=0; i<sizeof(WebColors)/sizeof(WebColors[0]); i++) {
+        display.background(WebColors[i]);
+        display.puts(" ");
+        if (i % 16 == 15 && i < 255) {
+            display.printf("\r\n%X ", ((i+1)/16));
+        }
+    }
+    display.SetTextFontSize(1,1);
+}
+
+
+void PixelTest(RA8875 & display, Serial & pc)
+{
+    int i, c, x, y;
+
+    if (!SuppressSlowStuff)
+        pc.printf("Pixel Test\r\n");
+    display.background(Black);
+    display.foreground(Blue);
+    display.cls();
+    display.puts(0,0, "Pixel Test");
+    for (i=0; i<1000; i++) {
+        x = rand() % 480;
+        y = 16 + rand() % (272-16);
+        c = rand() % 16;
+        //pc.printf("  (%d,%d) - %d\r\n", x,y,r1);
+        display.pixel(x,y, display.DOSColor(c));
+    }
+}
+
+
+void LineTest(RA8875 & display, Serial & pc)
+{
+    int i, x, y, x2, y2;
+
+    if (!SuppressSlowStuff)
+        pc.printf("Line Test\r\n");
+    display.background(Black);
+    display.foreground(Blue);
+    display.cls();
+    display.puts(0,0, "Line Test");
+    for (i=0; i<16; i++) {
+        // Lines
+        x = rand() % 480;
+        y = rand() % 272;
+        x2 = rand() % 480;
+        y2 = rand() % 272;
+        display.line(x,y, x2,y2, display.DOSColor(i));
+    }
+    display.foreground(BrightRed);
+    display.foreground(BrightGreen);
+    display.foreground(BrightBlue);
+    display.line(55,50, 79,74, BrightRed);
+    display.line(57,50, 81,74, BrightGreen);
+    display.line(59,50, 83,74, BrightBlue);
+    // horz
+    display.line(30,40, 32,40, BrightRed);
+    display.line(30,42, 32,42, BrightGreen);
+    display.line(30,44, 32,44, BrightBlue);
+    // vert
+    display.line(20,40, 20,42, BrightRed);
+    display.line(22,40, 22,42, BrightGreen);
+    display.line(24,40, 24,42, BrightBlue);
+    // compare point to line-point
+    display.pixel(20,50, BrightRed);
+    display.pixel(22,50, BrightGreen);
+    display.pixel(24,50, BrightBlue);
+    display.line(20,52, 20,52, BrightRed);
+    display.line(22,52, 22,52, BrightGreen);
+    display.line(24,52, 24,52, BrightBlue);
+
+    // point
+    display.line(50,50, 50,50, Red);
+    display.line(52,52, 52,52, Green);
+    display.line(54,54, 54,54, Blue);
+    display.line(60,60, 60,60, BrightRed);
+    display.line(62,62, 62,62, BrightGreen);
+    display.line(64,64, 64,64, BrightBlue);
+    display.line(70,70, 70,70, DarkRed);
+    display.line(72,72, 72,72, DarkGreen);
+    display.line(74,74, 74,74, DarkBlue);
+}
+
+
+void RectangleTest(RA8875 & display, Serial & pc)
+{
+    int i, x1,y1, x2,y2;
+
+    if (!SuppressSlowStuff)
+        pc.printf("Rectangle Test\r\n");
+    display.background(Black);
+    display.foreground(Blue);
+    display.cls();
+    display.puts(0,0, "Rectangle Test");
+    for (i=0; i<16; i++) {
+        x1 = rand() % 240;
+        y1 = 50 + rand() % 200;
+        x2 = rand() % 240;
+        y2 = 50 + rand() % 200;
+        display.rect(x1,y1, x2,y2, display.DOSColor(i));
+
+        x1 = 240 + rand() % 240;
+        y1 = 50 + rand() % 200;
+        x2 = 240 + rand() % 240;
+        y2 = 50 + rand() % 200;
+        display.rect(x1,y1, x2,y2, FILL);
+    }
+}
+
+
+void LayerTest(RA8875 & display, Serial & pc)
+{
+    loc_t i, x1,y1, x2,y2, r1,r2;
+
+    if (!SuppressSlowStuff)
+        pc.printf("Layer Test\r\n");
+
+    display.SelectDrawingLayer(0);
+    display.background(Black);
+    display.foreground(Blue);
+    display.cls();
+    display.puts(0,0, "Layer 0");
+    for (i=0; i<16; i++) {
+        x1 = rand() % 240;
+        y1 = 50 + rand() % 200;
+        x2 = x1 + rand() % 100;
+        y2 = y1 + rand() % 100;
+        r1 = rand() % (x2 - x1)/2;
+        r2 = rand() % (y2 - y1)/2;
+        display.roundrect(x1,y1, x2,y2, r1,r2, display.DOSColor(i));
+        if (!SuppressSlowStuff)
+            wait_ms(20);
+    }
+    if (!SuppressSlowStuff)
+        wait_ms(1000);
+
+    display.SelectDrawingLayer(1);
+    display.background(Black);
+    display.foreground(Yellow);
+    display.cls();
+    display.puts(240,0, "Layer 1");
+    for (i=0; i<16; i++) {
+        x1 = 300 + rand() % 100;
+        y1 = 70 + rand() % 200;
+        r1 = rand() % min(y1 - 20, 100);
+        display.circle(x1,y1,r1, display.DOSColor(i));
+        if (!SuppressSlowStuff)
+            wait_ms(20);
+    }
+    display.SetLayerMode(RA8875::ShowLayer1);        // Show it after the build-up
+    if (!SuppressSlowStuff)
+        wait_ms(2000);
+
+    display.SelectDrawingLayer(0);
+    display.SetLayerMode(RA8875::ShowLayer0);        // Show Layer 0 again
+    if (!SuppressSlowStuff)
+        wait_ms(1000);
+    display.SetLayerMode(RA8875::TransparentMode);        // Transparent mode
+    if (!SuppressSlowStuff)
+        wait_ms(1000);
+    for (i=0; i<=8; i++) {
+        display.SetLayerTransparency(i, 8-i);
+        if (!SuppressSlowStuff)
+            wait_ms(200);
+    }
+
+    // Restore before we exit
+    display.SetLayerTransparency(0, 0);
+    display.SetLayerMode(RA8875::ShowLayer0);        // Restore to layer 0
+}
+
+
+void RoundRectTest(RA8875 & display, Serial & pc)
+{
+    loc_t i, x1,y1, x2,y2, r1,r2;
+
+    if (!SuppressSlowStuff)
+        pc.printf("Round Rectangle Test\r\n");
+    display.background(Black);
+    display.foreground(Blue);
+    display.cls();
+    display.puts(0,0, "Rounded Rectangle Test");
+
+    for (i=0; i<16; i++) {
+        x1 = rand() % 240;
+        y1 = 50 + rand() % 200;
+        x2 = x1 + rand() % 100;
+        y2 = y1 + rand() % 100;
+        r1 = rand() % (x2 - x1)/2;
+        r2 = rand() % (y2 - y1)/2;
+        display.roundrect(x1,y1, x2,y2, 5,8, display.DOSColor(i));
+
+        x1 = 240 + rand() % 240;
+        y1 = 50 + rand() % 200;
+        x2 = x1 + rand() % 100;
+        y2 = y1 + rand() % 100;
+        r1 = rand() % (x2 - x1)/2;
+        r2 = rand() % (y2 - y1)/2;
+        display.roundrect(x1,y1, x2,y2, r1,r2, FILL);
+    }
+}
+
+
+void TriangleTest(RA8875 & display, Serial & pc)
+{
+    int i, x1, y1, x2, y2, x3, y3;
+
+    if (!SuppressSlowStuff)
+        pc.printf("Triangle Test\r\n");
+    display.background(Black);
+    display.foreground(Blue);
+    display.cls();
+    display.puts(0,0, "Triangle Test");
+
+    x1 = 150;
+    y1 = 2;
+    x2 = 190;
+    y2 = 7;
+    x3 = 170;
+    y3 = 16;
+    display.triangle(x1,y1, x2,y2, x3,y3);
+
+    x1 = 200;
+    y1 = 2;
+    x2 = 240;
+    y2 = 7;
+    x3 = 220;
+    y3 = 16;
+    display.filltriangle(x1,y1, x2,y2, x3,y3, BrightRed);
+
+    x1 = 300;
+    y1 = 2;
+    x2 = 340;
+    y2 = 7;
+    x3 = 320;
+    y3 = 16;
+    display.triangle(x1,y1, x2,y2, x3,y3, NOFILL);
+
+    x1 = 400;
+    y1 = 2;
+    x2 = 440;
+    y2 = 7;
+    x3 = 420;
+    y3 = 16;
+    display.triangle(x1,y1, x2,y2, x3,y3, Blue);
+
+    for (i=0; i<16; i++) {
+        x1 = rand() % 240;
+        y1 = 50 + rand() % 200;
+        x2 = rand() % 240;
+        y2 = 50 + rand() % 200;
+        x3 = rand() % 240;
+        y3 = 50 + rand() % 200;
+        display.triangle(x1,y1, x2,y2, x3,y3, display.DOSColor(i));
+        x1 = 240 + rand() % 240;
+        y1 = 50 + rand() % 200;
+        x2 = 240 + rand() % 240;
+        y2 = 50 + rand() % 200;
+        x3 = 240 + rand() % 240;
+        y3 = 50 + rand() % 200;
+        display.triangle(x1,y1, x2,y2, x3,y3, FILL);
+    }
+}
+
+
+void CircleTest(RA8875 & display, Serial & pc)
+{
+    int i, x, y, r1;
+
+    if (!SuppressSlowStuff)
+        pc.printf("Circle Test\r\n");
+    display.background(Black);
+    display.foreground(Blue);
+    display.cls();
+    display.puts(0,0, "Circle Test");
+    for (i=0; i<16; i++) {
+        x = 100 + rand() % 100;
+        y = 70 + rand() % 200;
+        r1 = rand() % min(y - 20, 100);
+        //pc.printf("  (%d,%d) - %d\r\n", x,y,r1);
+        display.circle(x,y,r1, display.DOSColor(i));
+
+        x = 300 + rand() % 100;
+        y = 70 + rand() % 200;
+        r1 = rand() % min(y - 20, 100);
+        //pc.printf("  (%d,%d) - %d FILL\r\n", x,y,r1);
+        display.circle(x,y,r1, display.DOSColor(i), FILL);
+    }
+}
+
+
+void EllipseTest(RA8875 & display, Serial & pc)
+{
+    int i,x,y,r1,r2;
+
+    if (!SuppressSlowStuff)
+        pc.printf("Ellipse Test\r\n");
+    display.background(Black);
+    display.foreground(Blue);
+    display.cls();
+    display.puts(0,0, "Ellipse Test");
+    for (i=0; i<16; i++) {
+        x = 100 + rand() % 100;
+        y = 70 + rand() % 200;
+        r1 = rand() % min(y - 20, 100);
+        r2 = rand() % min(y - 20, 100);
+        display.ellipse(x,y,r1,r2, display.DOSColor(i));
+
+        x = 300 + rand() % 100;
+        y = 70 + rand() % 200;
+        r1 = rand() % min(y - 20, 100);
+        r2 = rand() % min(y - 20, 100);
+        display.ellipse(x,y,r1,r2, FILL);
+    }
+}
+
+
+void TestGraphicsBitmap(RA8875 & display, Serial & pc)
+{
+    LocalFileSystem local("local");
+    if (!SuppressSlowStuff)
+        pc.printf("Bitmap File Load\r\n");
+    display.background(Black);
+    display.foreground(Blue);
+    display.cls();
+    display.puts(0,0, "Graphics Test, loading /local/TestPat.bmp");
+    wait(3);
+
+    int r = display.RenderBitmapFile(0,0, "/local/TestPat.bmp");
+    if (!SuppressSlowStuff)
+        pc.printf("  returned %d\r\n", r);
+}
+
+
+void TouchPanelTest(RA8875 & display, Serial & pc)
+{
+    Timer t;
+    loc_t x, y;
+    tpMatrix_t calmatrix;
+    
+    display.background(Black);
+    display.foreground(Blue);
+    display.cls();
+    display.puts(0,0, "Touch Panel Test\r\n");
+    pc.printf("Touch Panel Test\r\n");
+    display.TouchPanelInit();
+    pc.printf("  TP: c - calibrate, r - restore, t - test\r\n");
+    int c = pc.getc();
+    if (c == 'c') {
+        point_t pTest[3] =
+        { { 50, 50 }, {450, 150}, {225,250} };
+        point_t pSample[3];
+        for (int i=0; i<3; i++) {
+            display.foreground(Blue);
+            display.printf(" (%3d,%3d) => ", pTest[i].x, pTest[i].y);
+            display.line(pTest[i].x-10, pTest[i].y, pTest[i].x+10, pTest[i].y, White);
+            display.line(pTest[i].x, pTest[i].y-10, pTest[i].x, pTest[i].y+10, White);
+            while (!display.TouchPanelA2DFiltered(&x, &y))
+                wait_ms(20);
+            pSample[i].x = x;
+            pSample[i].y = y;
+            display.line(pTest[i].x-10, pTest[i].y, pTest[i].x+10, pTest[i].y, Black);
+            display.line(pTest[i].x, pTest[i].y-10, pTest[i].x, pTest[i].y+10, Black);
+            display.foreground(Blue);
+            display.printf(" (%4d,%4d)\r\n", x,y);
+            while (display.TouchPanelA2DFiltered(&x, &y))
+                wait_ms(20);
+            wait(2);
+        }
+        display.TouchPanelComputeCalibration(pTest, pSample, &calmatrix);
+        display.printf(" Writing calibration to tpcal.cfg\r\n");
+        FILE * fh = fopen("/local/tpcal.cfg", "wb");
+        if (fh) {
+            fwrite(&calmatrix, sizeof(calmatrix), 1, fh);
+            fclose(fh);
+        }
+        display.printf(" Calibration is complete.");
+    } else if (c == 'r') {
+        display.printf(" Reading calibration from tpcal.cfg\r\n");
+        FILE * fh = fopen("/local/tpcal.cfg", "rb");
+        if (fh) {
+            fread(&calmatrix, sizeof(calmatrix), 1, fh);
+            fclose(fh);
+        }
+        display.printf(" Calibration is complete.");
+        display.TouchPanelSetMatrix(&calmatrix);
+    }
+    t.start();
+    do {
+        point_t point = {0, 0};
+        if (display.TouchPanelReadable(&point)) {
+            display.pixel(point.x, point.y, Red);
+        }
+    } while (t.read_ms() < 30000);
+    pc.printf(">");
+}
+
+
+void SpeedTest(RA8875 & display, Serial & pc)
+{
+    Timer t;
+    SuppressSlowStuff = true;
+    pc.printf("\r\nSpeedTest disables delays, runs tests, reports overall time.\r\n");
+    t.start();
+    // do stuff fast
+    TextCursorTest(display, pc);
+    TextWrapTest(display, pc);
+    BacklightTest(display, pc, 0);
+    BacklightTest2(display, pc);
+    ExternalFontTest(display, pc);
+    DOSColorTest(display, pc);
+    WebColorTest(display, pc);
+    PixelTest(display, pc);
+    LineTest(display, pc);
+    RectangleTest(display, pc);
+    RoundRectTest(display, pc);
+    TriangleTest(display, pc);
+    CircleTest(display, pc);
+    EllipseTest(display, pc);
+    LayerTest(display, pc);
+    //TestGraphicsBitmap(display, pc);
+    pc.printf("SpeedTest completed in %d msec\r\n", t.read_ms());
+#ifdef PERF_METRICS
+    display.ReportPerformance(pc);
+#endif
+    SuppressSlowStuff = false;
+}
+
+
+void PrintScreen(RA8875 & display, Serial & pc)
+{
+    if (!SuppressSlowStuff)
+        pc.printf("PrintScreen\r\n");
+    display.PrintScreen( 0,0, 480,272, "/local/Capture.bmp");
+}
+
+
+void RunTestSet(RA8875 & lcd, Serial & pc)
+{
+    int q = 0;
+    int automode = 0;
+    const unsigned char modelist[] = "BDWtGLlFROTPCEbw";   // auto-test in this order.
+
+    while(1) {
+        pc.printf("\r\n"
+                  "B - Backlight up      b - backlight dim\r\n"
+                  "D - DOS Colors        W - Web Colors\r\n"
+                  "t - text cursor       G - Graphics Bitmap\r\n"
+                  "L - Lines             F - external Font\r\n"
+                  "R - Rectangles        O - rOund rectangles\r\n"
+                  "T - Triangles         P - Pixels  \r\n"
+                  "C - Circles           E - Ellipses\r\n"
+                  "A - Auto Test mode    S - Speed Test\r\n"
+                  "K - Keypad Test       s - touch screen test\r\n"
+                  "p - print screen      r - reset  \r\n"
+                  "l - layer test        w - wrapping text \r\n"
+#ifdef PERF_METRICS
+                  "0 - clear performance 1 - report performance\r\n"
+#endif
+                  "> ");
+        if (automode == -1 || pc.readable()) {
+            automode = -1;
+            q = pc.getc();
+            while (pc.readable())
+                pc.getc();
+        } else if (automode >= 0) {
+            q = modelist[automode];
+        }
+        switch(q) {
+#ifdef PERF_METRICS
+            case '0':
+                lcd.ClearPerformance();
+                break;
+            case '1':
+                lcd.ReportPerformance(pc);
+                break;
+#endif
+            case 'A':
+                automode = 0;
+                break;
+            case 'B':
+                BacklightTest(lcd, pc, 2);
+                break;
+            case 'b':
+                BacklightTest2(lcd, pc);
+                break;
+            case 'D':
+                DOSColorTest(lcd, pc);
+                break;
+            case 'K':
+                KeyPadTest(lcd, pc);
+                break;
+            case 'W':
+                WebColorTest(lcd, pc);
+                break;
+            case 't':
+                TextCursorTest(lcd, pc);
+                break;
+            case 'w':
+                TextWrapTest(lcd, pc);
+                break;
+            case 'F':
+                ExternalFontTest(lcd, pc);
+                break;
+            case 'L':
+                LineTest(lcd, pc);
+                break;
+            case 'l':
+                LayerTest(lcd, pc);
+                break;
+            case 'R':
+                RectangleTest(lcd, pc);
+                break;
+            case 'O':
+                RoundRectTest(lcd, pc);
+                break;
+            case 'p':
+                PrintScreen(lcd, pc);
+                break;
+            case 'S':
+                SpeedTest(lcd, pc);
+                break;
+            case 's':
+                TouchPanelTest(lcd, pc);
+                break;
+            case 'T':
+                TriangleTest(lcd, pc);
+                break;
+            case 'P':
+                PixelTest(lcd, pc);
+                break;
+            case 'G':
+                TestGraphicsBitmap(lcd, pc);
+                break;
+            case 'C':
+                CircleTest(lcd, pc);
+                break;
+            case 'E':
+                EllipseTest(lcd, pc);
+                break;
+            case 'r':
+                pc.printf("Resetting ...\r\n");
+                wait_ms(20);
+                mbed_reset();
+                break;
+            case ' ':
+                break;
+            default:
+                printf("huh?\n");
+                break;
+        }
+        if (automode >= 0) {
+            automode++;
+            if (automode >= sizeof(modelist))
+                automode = 0;
+            wait_ms(2000);
+        }
+        wait_ms(200);
+    }
+}
+
+#endif // TESTENABLE
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/RA8875/RA8875.h	Mon Nov 30 11:13:18 2015 +0000
@@ -0,0 +1,1864 @@
+///
+/// @mainpage RA8875 Display Controller Driver library
+///
+/// The RA8875 Display controller is a powerful interface for low cost displays. It
+/// can support displays up to 800 x 600 pixels x 16-bit color. Another common 
+/// implementation is 480 x 272 x 16 with two layers. The two layers can be 
+/// exchanged, or blended in various ways (transparency, OR, AND, and more).
+/// It includes graphics acceleration capabilities for drawing primitives, 
+/// such as line, rectangle, circles, and more.
+///
+/// The controller additionally supports backlight control (via PWM), keypad scanning
+/// (for a 4 x 5 matrix) and resistive touch-panel support. 
+///
+/// @section Display_Config Display Configuration
+///
+/// This section details basics for bringing the display online. At a minimum,
+/// the display is instantiated. After that any of the available commands
+/// may be issued.
+///
+/// During the instantiation, the display is powered on, cleared, and the backlight
+/// is energized. Additionally, the keypad and touchscreen features are activated.
+/// It is important to keep in mind that the keypad had the default mapping, and
+/// the touchscreen does not have the calibration matrix configured, so additional
+/// steps may be necessary.
+/// 
+/// @code 
+/// RA8875 lcd(p5, p6, p7, p12, NC, "tft");
+/// lcd.init();
+/// lcd.foreground(Blue);
+/// lcd.line(0,0, 479,271);
+/// ...
+/// @endcode
+///
+/// @section Touch_Panel Touch Panel
+///
+/// The supported touch panel interface is for a resistive panel, and is natively 
+/// supported by the RA8875 controller. There are a few steps to enable this interface.
+///
+/// @subsection Touch_Panel_Enable Touch Panel Enable
+///
+/// @see TouchPanelInit has two forms - fully automatic, and controlled. See the APIs for
+/// details.
+///
+/// @subsection Touch_Panel_Calibration
+/// 
+/// The touch panel is not initially calibrated on startup. The application should 
+/// provide a means to activate the calibration process, and that should not require
+/// the touchscreen as it may not yet be usable. Alternately, a calibration matrix
+/// can be loaded from non-volatile and installed.
+///
+/// @section Keypad Keypad
+///
+/// The keypad has a default keypad mapping, but there is an API that permits
+/// installing a custom keymap.
+///
+#ifndef RA8875_H
+#define RA8875_H
+#include <mbed.h>
+
+#include "RA8875_Regs.h"
+#include "GraphicsDisplay.h"
+
+#define RA8875_DEFAULT_SPI_FREQ 5000000
+
+// Define this to enable code that monitors the performance of various
+// graphics commands.
+//#define PERF_METRICS
+
+// What better place for some test code than in here and the companion
+// .cpp file. See also the bottom of this file.
+//#define TESTENABLE
+
+/// DOS colors - slightly color enhanced
+#define Black       (color_t)(RGB(0,0,0))
+#define Blue        (color_t)(RGB(0,0,187))
+#define Green       (color_t)(RGB(0,187,0))
+#define Cyan        (color_t)(RGB(0,187,187))
+#define Red         (color_t)(RGB(187,0,0))
+#define Magenta     (color_t)(RGB(187,0,187))
+#define Brown       (color_t)(RGB(63,63,0))
+#define Gray        (color_t)(RGB(187,187,187))
+#define Charcoal    (color_t)(RGB(85,85,85))
+#define BrightBlue  (color_t)(RGB(0,0,255))
+#define BrightGreen (color_t)(RGB(0,255,0))
+#define BrightCyan  (color_t)(RGB(0,255,255))
+#define BrightRed   (color_t)(RGB(255,0,0))
+#define Orange      (color_t)(RGB(255,85,85))
+#define Pink        (color_t)(RGB(255,85,255))
+#define Yellow      (color_t)(RGB(187,187,0))
+#define White       (color_t)(RGB(255,255,255))
+
+#define DarkBlue    (color_t)(RGB(0,0,63))
+#define DarkGreen   (color_t)(RGB(0,63,0))
+#define DarkCyan    (color_t)(RGB(0,63,63))
+#define DarkRed     (color_t)(RGB(63,0,0))
+#define DarkMagenta (color_t)(RGB(63,0,63))
+#define DarkBrown   (color_t)(RGB(63,63,0))
+#define DarkGray    (color_t)(RGB(63,63,63))
+
+
+//namespace SW_graphics
+//{
+
+
+/// This is a graphics library for the Raio RA8875 Display Controller chip
+/// attached to a 4-wire SPI interface.
+///
+/// It offers both primitive and high level APIs.
+///
+/// Central to this API is a coordinate system, where the origin (0,0) is in
+/// the top-left corner of the display, and the width (x) extends positive to the
+/// right and the height (y) extends positive toward the bottom.
+///
+/// @caution As there are both graphics and text commands, one must take care to use
+/// the proper coordinate system for each. Some of the text APIs are in units
+/// of column and row, which is measured in character positions (and dependent
+/// on the font size), where other text APIs permit pixel level positioning.
+///
+/// @code
+/// #include "RA8875.h"
+/// RA8875 lcd(p5, p6, p7, p12, NC, "tft");
+///
+/// int main()
+/// {
+///     lcd.init();
+///     lcd.printf("printing 3 x 2 = %d", 3*2);
+///     lcd.circle(       400,25,  25,               BrightRed);
+///     lcd.fillcircle(   400,25,  15,               RGB(128,255,128));
+///     lcd.ellipse(      440,75,  35,20,            BrightBlue);
+///     lcd.fillellipse(  440,75,  25,10,            Blue);
+///     lcd.triangle(     440,100, 475,110, 450,125, Magenta);
+///     lcd.filltriangle( 445,105, 467,111, 452,120, Cyan);
+///     lcd.rect(         400,130, 475,155,          Brown);
+///     lcd.fillrect(     405,135, 470,150,          Pink);
+///     lcd.roundrect(    410,160, 475,190, 10,8,    Yellow);
+///     lcd.fillroundrect(415,165, 470,185,  5,3,    Orange);
+///     lcd.line(         430,200, 460,230,          RGB(0,255,0));
+///     for (int i=0; i<=30; i+=5) 
+///         lcd.pixel(435+i,200+i, White);
+/// }
+/// @endcode
+///
+/// @todo Add Scroll support for text.
+/// @todo Improve sync between internal and external font support - cursor, window, scroll.
+/// @todo Add Hardware reset signal - but testing to date indicates it is not needed.
+/// @todo Add high level objects - x-y graph, meter, others... but these will
+///     probably be best served in another class, since they may not
+///     be needed for many uses.
+/// 
+class RA8875 : public GraphicsDisplay
+{
+public:   
+    /// cursor type to be shown as the text cursor.
+    typedef enum
+    {
+        NOCURSOR,   ///< cursor is hidden
+        IBEAM,      ///< | cursor
+        UNDER,      ///< _ cursor
+        BLOCK       ///< Block cursor
+    } cursor_t;
+
+    /// font type selection.
+    typedef enum
+    {
+        ISO8859_1,      ///< ISO8859-1 font
+        ISO8859_2,      ///< ISO8859-2 font
+        ISO8859_3,      ///< ISO8859-3 font
+        ISO8859_4       ///< ISO8859-4 font
+    } font_t;
+    
+    /// font rotation selection
+    typedef enum
+    {
+        normal,         ///< normal orientation
+        rotated         ///< rotated orientation
+    } font_angle_t;
+    
+    /// alignment  
+    typedef enum
+    {
+        align_none,     ///< align - none
+        align_full      ///< align - full
+    } alignment_t;    
+    
+    /// Scale factor - 1, 2, 3 4
+    typedef int HorizontalScale;
+    
+    /// Scale factor - 1, 2, 3, 4
+    typedef int VerticalScale;
+
+    /// Clear screen region
+    typedef enum
+    {
+        FULLWINDOW,     ///< Full screen
+        ACTIVEWINDOW    ///< active window/region
+    } Region_t;
+    
+    /// Set the Layer Display Mode. @ref SetLayerMode
+    typedef enum
+    {
+        ShowLayer0,         ///< Only layer 0 is visible, layer 1 is hidden (default)
+        ShowLayer1,         ///< Only layer 1 is visible, layer 0 is hidden
+        LightenOverlay,     ///< Lighten-overlay mode
+        TransparentMode,    ///< Transparent mode
+        BooleanOR,          ///< Boolean OR mode
+        BooleanAND,         ///< Boolean AND mode
+        FloatingWindow      ///< Floating Window mode
+    } LayerMode_T;
+    
+    /// Touch Panel modes
+    typedef enum
+    {
+        TP_Auto,               ///< Auto touch detection mode
+        TP_Manual,             ///< Manual touch detection mode
+    } tpmode_t;
+    
+    /// Constructor for a display based on the RAiO RA8875 
+    /// display controller.
+    ///
+    /// This configures the registers and calls the @ref init method.
+    ///
+    /// @code
+    /// #include "RA8875.h"
+    /// RA8875 lcd(p5, p6, p7, p12, NC, "tft");
+    ///
+    /// int main()
+    /// {
+    ///     lcd.init();
+    ///     lcd.printf("printing 3 x 2 = %d", 3*2);
+    ///     lcd.circle(400,25, 25, BrightRed);
+    /// }
+    /// @endcode
+    ///
+    /// @param[in] mosi is the SPI master out slave in pin on the mbed.
+    /// @param[in] miso is the SPI master in slave out pin on the mbed.
+    /// @param[in] sclk is the SPI shift clock pin on the mbed.
+    /// @param[in] csel is the DigitalOut pin on the mbed to use as the
+    ///         active low chip select for the display controller.
+    /// @param[in] reset is the DigitalOut pin on the mbed to use as the 
+    ///         active low reset input on the display controller - 
+    ///         but this is not currently used.
+    /// @param[in] name is a text name for this object, which will permit
+    ///         capturing stdout to puts() and printf() directly to it.
+    ///
+    RA8875(PinName mosi, PinName miso, PinName sclk, PinName csel, PinName reset, const char * name = "lcd");
+    
+    // Destructor doesn't have much to do as this would typically be created
+    // at startup, and not at runtime.
+    //~RA8875();
+    
+    /// Initialize the driver.
+    ///
+    /// @param[in] width in pixels to configure the display for. This parameter is optional
+    ///             and the default is 480.
+    /// @param[in] height in pixels to configure the display for. This parameter is optional
+    ///             and the default is 272.
+    /// @param[in] color_bpp can be either 8 or 16, but must be consistent
+    ///             with the width and height parameters. This parameter is optional
+    ///             and the default is 16.
+    /// @param[in] power defines if the display should be left in the power-on or off state.
+    ///            If power is true (on), the backlight is set to 100%. This parameter is optional
+    ///             and the default is true (on). @see Power.
+    /// @param[in] keypadon defines if the keypad support should be enabled. This parameter is optional
+    ///             and the default is true (enabled). @see KeypadInit.
+    /// @param[in] touchscreeenon defines if the keypad support should be enabled. This parameter is optional
+    ///             and the default is true (enabled). @see TouchPanelInit.
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    RetCode_t init(int width = 480, int height = 272, int color_bpp = 16, 
+        bool poweron = true, bool keypadon = true, bool touchscreeenon = true);
+    
+    /// Get a pointer to the error code.
+    ///
+    /// This method returns a pointer to a text string that matches the
+    /// code. @see RetCode_t.
+    ///
+    /// @param[in] code is the return value from RetCode_t to look up.
+    /// @returns a pointer to the text message representing code. If code
+    ///     is not a valid value, then it returns the text for bad_parameter;
+    const char * GetErrorMessage(RetCode_t code);
+    
+    
+    /// Select the drawing layer for subsequent commands.
+    ///
+    /// If the screen configuration is 480 x 272, or if it is 800 x 480 
+    /// and 8-bit color, the the display supports two layers, which can 
+    /// be independently drawn on and shown. Additionally, complex
+    /// operations involving both layers are permitted.
+    ///
+    /// @code
+    ///     //lcd.SetLayerMode(OnlyLayer0); // default is layer 0
+    ///     lcd.rect(400,130, 475,155,Brown);
+    ///     lcd.SelectDrawingLayer(1);
+    ///     lcd.circle(400,25, 25, BrightRed);
+    ///     wait(1);
+    ///     lcd.SetLayerMode(ShowLayer1);
+    /// @endcode
+    ///
+    /// @attention The user manual refers to Layer 1 and Layer 2, however the
+    ///     actual register values are value 0 and 1. This API as well as
+    ///     others that reference the layers use the values 0 and 1 for
+    ///     cleaner iteration in the code.
+    ///
+    /// @param[in] layer is 0 or 1 to select the layer for subsequent 
+    ///     commands.
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    RetCode_t SelectDrawingLayer(uint16_t layer);
+    
+    /// Get the currently active drawing layer.
+    ///
+    /// This returns a value, 0 or 1, based on the screen configuration
+    /// and the currently active drawing layer.
+    ///
+    /// @code
+    ///     uint16_t prevLayer = lcd.GetDrawingLayer();
+    ///     lcd.SelectDrawingLayer(x);
+    ///     lcd.circle(400,25, 25, BrightRed);
+    ///     lcd.SelectDrawingLayer(prevLayer);
+    /// @endcode
+    ///
+    /// @attention The user manual refers to Layer 1 and Layer 2, however the
+    ///     actual register values are value 0 and 1. This API as well as
+    ///     others that reference the layers use the values 0 and 1 for
+    ///     cleaner iteration in the code.
+    ///
+    /// @returns the current drawing layer; 0 or 1.
+    /// 
+    uint16_t GetDrawingLayer(void);
+    
+    /// Set the Layer presentation mode.
+    ///
+    /// This sets the presentation mode for layers, and permits showing
+    /// a single layer, or applying a mode where the two layers
+    /// are combined using one of the hardware methods.
+    ///
+    /// Refer to the RA8875 data sheet for full details.
+    ///
+    /// @code
+    ///     //lcd.SetLayerMode(OnlyLayer0); // default is layer 0
+    ///     lcd.rect(400,130, 475,155,Brown);
+    ///     lcd.SelectDrawingLayer(1);
+    ///     lcd.circle(400,25, 25, BrightRed);
+    ///     wait(1);
+    ///     lcd.SetLayerMode(ShowLayer1);
+    /// @endcode
+    ///
+    /// @param[in] mode sets the mode in the Layer Transparency Register.
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    RetCode_t SetLayerMode(LayerMode_T mode);
+    
+    /// Set the layer transparency for each layer.
+    ///
+    /// Set the transparency, where the range of values is
+    /// from zero (fully visible) to eight (fully transparent).
+    /// The input value is automatically limited to this range.
+    ///
+    /// @code
+    ///     // draw something on each layer, then step-fade across
+    ///     display.SetLayerMode(RA8875::TransparentMode);
+    ///     for (i=0; i<=8; i++) {
+    ///         display.SetLayerTransparency(i, 8-i);
+    ///         wait_ms(200);
+    ///     }
+    /// @endcode
+    ///
+    /// @param[in] layer1 sets the layer 1 transparency.
+    /// @param[in] layer2 sets the layer 2 transparency.
+    /// @returns success/failure code. @see RetCode_t.
+    /// 
+    RetCode_t SetLayerTransparency(uint8_t layer1, uint8_t layer2);
+    
+    /// Set the background color register used for transparency.
+    ///
+    /// This command sets the background color registers that are used
+    /// in the transparent color operations involving the layers.
+    /// 
+    /// @param[in] color is optional and expressed in 16-bit format. If not
+    ///     supplied, a default of Black is used.
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    RetCode_t SetBackgroundTransparencyColor(color_t color = RGB(0,0,0));
+ 
+ 
+    /// Get the background color value used for transparency.
+    ///
+    /// This command reads the background color registers that define
+    /// the transparency color for operations involving layers.
+    ///
+    /// @returns the color.
+    ///
+    color_t GetBackgroundTransparencyColor(void);
+ 
+    /// Initialize theTouch Panel controller with default values 
+    ///
+    /// This activates the simplified touch panel init, which may work for
+    /// most uses. The alternate API is available if fine-grained control
+    /// is needed for the numerous settings.
+    ///
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    RetCode_t TouchPanelInit(void);
+        
+    /// Initialize the Touch Panel controller with detailed settings.
+    ///
+    /// This is the detailed touch panel init, which provides the ability
+    /// to set nearly every possible option.
+    ///
+    /// @param[in]  bTpEnable           Touch Panel enable/disable control:
+    ///                                 - TP_ENABLE: enable the touch panel
+    ///                                 - TP_DISABLE: disable the touch panel
+    /// @param[in]  bTpAutoManual       Touch Panel operating mode:
+    ///                                 - TP_MODE_AUTO: automatic capture
+    ///                                 - TP_MODE_MANUAL: manual capture
+    /// @param[in]  bTpDebounce         Debounce circuit enable for touch panel interrupt:
+    ///                                 - TP_DEBOUNCE_OFF: disable the debounce circuit
+    ///                                 - TP_DEBOUNCE_ON: enable the debounce circuit     
+    /// @param[in]  bTpManualMode       When Manual Mode is selected, this sets the mode:
+    ///                                 - TP_MANUAL_IDLE: touch panel is idle   
+    ///                                 - TP_MANUAL_WAIT: wait for touch panel event   
+    ///                                 - TP_MANUAL_LATCH_X: latch X data  
+    ///                                 - TP_MANUAL_LATCH_Y: latch Y data   
+    /// @param[in]  bTpAdcClkDiv        Sets the ADC clock as a fraction of the System CLK:
+    ///                                 - TP_ADC_CLKDIV_1: Use CLK   
+    ///                                 - TP_ADC_CLKDIV_2: Use CLK/2   
+    ///                                 - TP_ADC_CLKDIV_4: Use CLK/4   
+    ///                                 - TP_ADC_CLKDIV_8: Use CLK/8   
+    ///                                 - TP_ADC_CLKDIV_16: Use CLK/16   
+    ///                                 - TP_ADC_CLKDIV_32: Use CLK/32   
+    ///                                 - TP_ADC_CLKDIV_64: Use CLK/64   
+    ///                                 - TP_ADC_CLKDIV_128: Use CLK/128   
+    /// @param[in]  bTpAdcSampleTime    Touch Panel sample time delay before ADC data is ready:
+    ///                                 - TP_ADC_SAMPLE_512_CLKS: Wait 512 system clocks   
+    ///                                 - TP_ADC_SAMPLE_1024_CLKS: Wait 1024 system clocks   
+    ///                                 - TP_ADC_SAMPLE_2048_CLKS: Wait 2048 system clocks   
+    ///                                 - TP_ADC_SAMPLE_4096_CLKS: Wait 4096 system clocks   
+    ///                                 - TP_ADC_SAMPLE_8192_CLKS: Wait 8192 system clocks   
+    ///                                 - TP_ADC_SAMPLE_16384_CLKS: Wait 16384 system clocks   
+    ///                                 - TP_ADC_SAMPLE_32768_CLKS: Wait 32768 system clocks   
+    ///                                 - TP_ADC_SAMPLE_65536_CLKS: Wait 65536 system clocks
+    /// @returns success/failure code. @see RetCode_t.   
+    ///
+    RetCode_t TouchPanelInit(uint8_t bTpEnable, uint8_t bTpAutoManual, uint8_t bTpDebounce, 
+        uint8_t bTpManualMode, uint8_t bTpAdcClkDiv, uint8_t bTpAdcSampleTime);
+    
+    /// Poll the TouchPanel and on a touch event return the a to d filtered x, y coordinates.
+    ///
+    /// This method reads the touch controller, which has a 10-bit range for each the
+    /// x and the y axis.
+    ///
+    /// @note The returned values are not in display (pixel) units but are in analog to
+    ///     digital converter units.
+    /// 
+    /// @note This API is usually not needed. @see TouchPanelComputeCalibration. 
+    ///     @see TouchPanelReadable.
+    /// 
+    /// @param[out] x is the x scale a/d value.
+    /// @param[out] y is the y scale a/d value.
+    /// @returns true if touch was detected, in which case the x and y values were set.
+    ///
+    bool TouchPanelA2DFiltered(loc_t *x, loc_t *y);
+
+    /// Poll the TouchPanel and on a touch event return the a to d raw x, y coordinates.
+    ///
+    /// This method reads the touch controller, which has a 10-bit range for each the
+    /// x and the y axis. A number of samples of the raw data are taken, filtered,
+    /// and the results are returned. 
+    ///
+    /// @note The returned values are not in display (pixel) units but are in analog to
+    ///     digital converter units.
+    /// 
+    /// @note This API is usually not needed. @see TouchPanelComputeCalibration. 
+    ///     @see TouchPanelReadable.
+    /// 
+    /// @param[out] x is the x scale a/d value.
+    /// @param[out] y is the y scale a/d value.
+    /// @returns true if touch was detected, in which case the x and y values were set.
+    ///
+    bool TouchPanelA2DRaw(loc_t *x, loc_t *y);
+    
+    /// Calibrate the touch panel.
+    ///
+    /// This method accepts two lists - one list is target points in ,
+    /// display coordinates and the other is a lit of raw touch coordinate 
+    /// values. It generates a calibration matrix for later use. This
+    /// matrix is also accessible to the calling API, which may store
+    /// the matrix in persistent memory and then install the calibration
+    /// matrix on the next power cycle. By doing so, it can avoid the
+    /// need to calibrate on every power cycle.
+    ///
+    /// @note The methods "TouchPanelComputeCalibration", "TouchPanelReadable", and
+    ///     indirectly the "TouchPanelSetMatrix" methods are all derived
+    ///     from a program by Carlos E. Vidales. See the copyright note
+    ///     for further details. See also the article
+    ///     http://www.embedded.com/design/system-integration/4023968/How-To-Calibrate-Touch-Screens
+    ///
+    /// @copyright Copyright (c) 2001, Carlos E. Vidales. All rights reserved.
+    ///     This sample program was written and put in the public domain 
+    ///      by Carlos E. Vidales.  The program is provided "as is" 
+    ///      without warranty of any kind, either expressed or implied.
+    ///     If you choose to use the program within your own products
+    ///      you do so at your own risk, and assume the responsibility
+    ///      for servicing, repairing or correcting the program should
+    ///      it prove defective in any manner.
+    ///     You may copy and distribute the program's source code in any 
+    ///      medium, provided that you also include in each copy an
+    ///      appropriate copyright notice and disclaimer of warranty.
+    ///     You may also modify this program and distribute copies of
+    ///      it provided that you include prominent notices stating 
+    ///      that you changed the file(s) and the date of any change,
+    ///      and that you do not charge any royalties or licenses for 
+    ///      its use.
+    ///
+    /// @param[in] display is a pointer to a set of 3 points, which 
+    ///             are in display units of measure. These are the targets
+    ///             the calibration was aiming for.
+    /// @param[in] screen is a pointer to a set of 3 points, which
+    ///             are in touchscreen units of measure. These are the
+    ///             registered touches.
+    /// @param[out] matrix is an optional parameter to hold the calibration matrix 
+    ///             as a result of the calibration. This can be saved in  
+    ///             non-volatile memory to recover the calibration after a power fail.
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    RetCode_t TouchPanelComputeCalibration(point_t display[3], point_t screen[3], tpMatrix_t * matrix);
+
+
+    /// Perform the touch panel calibration process.
+    ///
+    /// This method provides the easy "shortcut" to calibrating the touch panel.
+    /// The process will automatically generate the calibration points, present
+    /// the targets on-screen, detect the touches, compute the calibration
+    /// matrix, and optionally provide the calibration matrix to the calling code
+    /// for persistence in non-volatile memory.
+    ///
+    /// @param[out] matrix is an optional parameter to hold the calibration matrix 
+    ///             as a result of the calibration. This can be saved in  
+    ///             non-volatile memory to recover the calibration after a power fail.
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    RetCode_t TouchPanelCalibrate(tpMatrix_t * matrix);
+
+    /// Perform the touch panel calibration process.
+    ///
+    /// This method provides the easy "shortcut" to calibrating the touch panel.
+    /// The process will automatically generate the calibration points, present
+    /// the targets on-screen, detect the touches, compute the calibration
+    /// matrix, and optionally provide the calibration matrix to the calling code
+    /// for persistence in non-volatile memory.
+    ///
+    /// @param[in] msg is a text message to present on the screen during the
+    ///             calibration process.
+    /// @param[out] matrix is an optional parameter to hold the calibration matrix 
+    ///             as a result of the calibration. This can be saved in  
+    ///             non-volatile memory to recover the calibration after a power fail.
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    RetCode_t TouchPanelCalibrate(const char * msg, tpMatrix_t * matrix = NULL);
+
+    /// Get the screen calibrated point of touch.
+    ///
+    /// This method determines if there is a touch and if so it will provide
+    /// the screen-relative touch coordinates. This method can be used in
+    /// a manner similar to Serial.readable(), to determine if there was a 
+    /// touch and indicate that - but not care about the coordinates. Alternately,
+    /// if a valid pointer to a point_t is provided, then if a touch is detected
+    /// the point_t will be populated with data. 
+    ///
+    /// @code
+    ///     Timer t;
+    ///     t.start();
+    ///     do {
+    ///        point_t point = {0, 0};
+    ///        if (display.TouchPanelReadable(&point)) {
+    ///            display.pixel(point.x, point.y, Red);
+    ///        }
+    ///    } while (t.read_ms() < 30000);
+    /// @endcode
+    ///
+    /// @param[out] touch is the touch point, if a touch is registered.
+    /// @returns true if a touch was registered, and touch is updated.
+    /// @returns false if no touch was detected, or if the calibration matrix is not defined.
+    ///
+    bool TouchPanelReadable(point_t * touch = NULL);
+
+    /// Wait for a touch panel touch and return it.
+    /// 
+    /// This method is similar to Serial.getc() in that it will wait for a touch
+    /// and then return. In order to extract the coordinates of the touch, a
+    /// valid pointer to a point_t must be provided.
+    ///
+    /// @note There is no timeout on this function, so its use is not recommended.
+    ///
+    /// @code
+    ///     Timer t;
+    ///     t.start();
+    ///     do {
+    ///        point_t point = {0, 0};
+    ///        display.TouchPanelGet(&point);
+    ///        display.pixel(point.x, point.y, Red);
+    ///    } while (t.read_ms() < 30000);
+    /// @endcode
+    ///
+    /// @param[out] touch is the touch point, if a touch is registered.
+    /// @returns true if a touch was registered, and touch is updated.
+    /// @returns false if no touch was detected, or if the calibration matrix is not defined.
+    ///
+    bool TouchPanelGet(point_t * touch);
+
+    /// Set the calibration matrix for the touch panel.
+    ///
+    /// This method is used to set the calibration matrix for the touch panel. After
+    /// performing the calibration (@see TouchPanelComputeCalibration), the matrix can be stored.
+    /// On a subsequence power cycle, the matrix may be restored from non-volatile and
+    /// passed in to this method. It will then be held to perform the corrections when
+    /// reading the touch panel point.
+    ///
+    /// @code
+    /// FILE * fh = fopen("/local/tpmatrix.cfg", "r");
+    /// if (fh) {
+    ///     tpMatrix_t matrix;
+    ///     if (fread(fh, &matrix, sizeof(tpMatrix_t))) {
+    ///         lcd.TouchPanelSetMatrix(&matrix);
+    ///     }
+    ///     fclose(fh);
+    /// }
+    /// @endcode
+    /// 
+    /// @param[in] matrix is a pointer to the touch panel calibration matrix.
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    RetCode_t TouchPanelSetMatrix(tpMatrix_t * matrix);
+   
+#if 0
+    /// Append interrupt handler for specific RA8875 interrupt source
+    ///
+    /// @param[in]    bISRType        Interrupt Source, should be:
+    ///                                - RA8875_INT_KEYSCAN: KEYCAN interrupt
+    ///                                - RA8875_INT_DMA: DMA interrupt
+    ///                                - RA8875_INT_TP: Touch panel interrupt
+    ///                                - RA8875_INT_BTE: BTE process complete interrupt
+    ///                                - RA8875_INT_BTEMCU_FONTWR: Multi-purpose interrupt (see spec sheet)   
+    /// @param[in]    fptr is a callback function to handle the interrupt event.
+    /// @returns       none
+    ///
+    void AppendISR(uint8_t bISRType, void(*fptr)(void));
+
+    /// Unappend interrupt handler for specific RA8875 interrupt source
+    ///
+    /// @param[in]    bISRType        Interrupt Source, should be:
+    ///                                - RA8875_INT_KEYSCAN: KEYCAN interrupt
+    ///                                - RA8875_INT_DMA: DMA interrupt
+    ///                                - RA8875_INT_TP: Touch panel interrupt
+    ///                                - RA8875_INT_BTE: BTE process complete interrupt
+    ///                                - RA8875_INT_BTEMCU_FONTWR: Multi-purpose interrupt (see spec sheet)   
+    /// @return       none
+    ///
+    void UnAppendISR(uint8_t bISRType);
+#endif
+
+    /// Initialize the keypad interface on the RA8875 controller.
+    ///
+    /// Enables the keypad subsystem. It will scan the 4 x 5 matrix
+    /// and make available key presses. 
+    ///
+    /// @note See section 5-13 of RAIO RA8875 data sheet for more details.
+    /// @caution When using the display from buy-display.com, be sure that
+    ///     the option for the keypad is configured on the hardware.
+    ///
+    /// All parameters are optional.
+    /// @param[in] scanEnable when true, enables the key scan function (default: true).
+    /// @param[in] longDetect when true, additionally enables the long key held detection (default: false).
+    /// @param[in] sampleTime setting (range: 0 - 3, default: 0).
+    /// @param[in] scanFrequency setting (range: 0 - 7, default: 0).
+    /// @param[in] longTimeAdjustment (range: 0 - 3, default: 0).
+    /// @param[in] interruptEnable when true, enables interrupts from keypress (default: false).
+    /// @param[in] wakeupEnable when true, activates the wakeup function (default: false).
+    ///
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    RetCode_t  KeypadInit(bool scanEnable = true, bool longDetect = false, 
+        uint8_t sampleTime = 0, uint8_t scanFrequency = 0, 
+        uint8_t longTimeAdjustment = 0,
+        bool interruptEnable = false, bool wakeupEnable = false);
+
+    /// Create Key Code definitions for the key matrix.
+    ///
+    /// This API provides a table of 22 key-code assignments for the matrix of keys.
+    /// This can be used to translate the keys 1 - 20 into some other value, as
+    /// well as to communicate the "no key" (zero) and "error state" (21).
+    ///
+    /// In this way, a keypad could easily emulate a piece of a keyboard, transforming
+    /// 0 - 20 into the values 0, '0', '1', '2', '3', '4', '5', '6', '7', '8',
+    /// '9', '+', '-', '*' , '/', '=', '<bs>', '<cr>', and so on...
+    ///
+    /// @code
+    /// //        Return Value by Row, Column   Example reassignment
+    /// //    Column    0    1    2    3    4 
+    /// //          +-------------------------+  +-------------------------+
+    /// // Row   0  |   1    2    3    4    5 |  | '7'  '8'  '9'  ',' '<-' |
+    /// //       1  |   6    7    8    9   10 |  | '4'  '5'  '6'  '/'  '-' |
+    /// //       2  |  11   12   13   14   15 |  | '1'  '2'  '3'  '*'  '+' |
+    /// //       3  |  16   17   18   19   20 |  | '0'  '.'  '('  ')' '\n' |
+    /// //          +-------------------------+  +-------------------------+
+    /// //     Return value  0 = No Key pressed
+    /// //     Return value 21 = Error
+    /// const uint8_t CodeList[22] = 
+    ///     {0, '7', '8', '9', ',', '\h', 
+    ///         '4', '5', '6', '/', '-',
+    ///         '1', '2', '3', '*', '+',
+    ///         '0', '.', '(', ')', '\n', 
+    ///         '\x1b'};
+    ///     lcd.SetKeyMap(CodeList);
+    /// @endcode
+    /// 
+    /// @param[in] CodeList is a pointer to an always available byte-array 
+    ///             where the first 22 bytes are used as the transformation 
+    ///             from raw code to your reassigned value.
+    ///            If CodeList is NULL, the original raw value key map is
+    ///             restored.
+    /// @returns noerror.
+    ///
+    RetCode_t SetKeyMap(const uint8_t * CodeList = NULL);
+
+    /// Determine if a key has been hit
+    ///
+    /// @returns true if a key has been hit
+    ///
+    bool readable();
+
+    /// Blocking read of the keypad.
+    ///
+    /// @caution: This is a blocking read, so it is important to first call _kbhit()
+    ///         to avoid hanging your processes.
+    ///
+    /// A keypad connected to the RA8875 is connected in a matrix of 4 rows and 5 columns.
+    /// When pressed, this method will return a code in the range of 1 through 20, reserving
+    /// the value 0 to indicate that no key is pressed.
+    ///
+    /// Additionally, if configured to detect a "long press", bit 7 will be set to indicate
+    /// this. In this situation, first a "normal press" would be detected and signaled and
+    /// soon after that a "long press" of the same key would be detected and communicated.
+    ///
+    /// @return 8-bit where bit 7 indicates a long press. The remaining bits indicate the
+    ///     keypress using 0 = no key pressed, 1 - 20 = the key pressed.
+    ///
+    uint8_t getc();
+    
+    /// Write a command to the display with a word of data.
+    ///
+    /// This is a high level command, and may invoke several primitives.
+    ///
+    /// @param[in] command is the command to write.
+    /// @param[in] data is data to be written to the command register.
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    RetCode_t WriteCommandW(uint8_t command, uint16_t data);
+
+    /// Write a command to the display
+    ///
+    /// This is a high level command, and may invoke several primitives.
+    ///
+    /// @param[in] command is the command to write.
+    /// @param[in] data is optional data to be written to the command register
+    ///     and only occurs if the data is in the range [0 - 0xFF].
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    virtual RetCode_t WriteCommand(unsigned char command, unsigned int data = 0xFFFF);
+    
+    /// Write a data word to the display
+    ///
+    /// This is a high level command, and may invoke several primitives.
+    ///
+    /// @param[in] data is the data to write.
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    RetCode_t WriteDataW(uint16_t data);
+    
+    /// Write a data byte to the display
+    ///
+    /// This is a high level command, and may invoke several primitives.
+    ///
+    /// @param[in] data is the data to write.
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    virtual RetCode_t WriteData(unsigned char data);
+    
+    /// Read a command register
+    ///
+    /// @param[in] command is the command register to read.
+    /// @returns the value read from the register.
+    ///
+    unsigned char ReadCommand(unsigned char command);
+    
+    /// Read a data byte from the display
+    ///
+    /// This is a high level command, and may invoke several primitives.
+    ///
+    /// @returns data that was read.
+    ///
+    unsigned char ReadData(void);
+    
+    /// Read a word from the display
+    ///
+    /// This is a high level command, and may invoke several primitives.
+    ///
+    /// @returns data that was read.
+    ///
+    uint16_t ReadDataW(void);
+
+    /// Read the display status
+    ///
+    /// This is a high level command, and may invoke several primitives.
+    ///
+    /// @returns data that was read.
+    ///
+    unsigned char ReadStatus(void);
+
+    /// get the width in pixels of the currently active font
+    ///
+    /// @returns font width in pixels.
+    ///    
+    dim_t fontwidth(void);
+    
+    /// get the height in pixels of the currently active font
+    ///
+    /// @returns font height in pixels.
+    ///    
+    dim_t fontheight(void);
+    
+    /// get the number of colums based on the currently active font
+    ///
+    /// @returns number of columns.
+    ///    
+    virtual int columns(void);
+
+    /// get the number of rows based on the currently active font
+    ///
+    /// @returns number of rows.
+    ///    
+    virtual int rows(void);
+
+    /// get the screen width in pixels
+    ///
+    /// @returns screen width in pixels.
+    ///
+    virtual dim_t width(void);
+
+    /// get the screen height in pixels
+    ///
+    /// @returns screen height in pixels.
+    ///
+    virtual dim_t height(void);
+
+    /// get the color depth in bits per pixel.
+    ///
+    /// @returns 8 or 16 only.
+    ///
+    virtual dim_t color_bpp(void);
+
+    /// Set cursor position based on the current font size.
+    /// 
+    /// @param[in] column is the horizontal position in character positions
+    /// @param[in] row is the vertical position in character positions
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    virtual RetCode_t locate(textloc_t column, textloc_t row);
+
+    /// Prepare the controller to write text to the screen by positioning
+    /// the cursor.
+    ///
+    /// @code
+    ///     lcd.SetTextCursor(100, 25);
+    ///     lcd.puts("Hello");
+    /// @endcode
+    ///
+    /// @param[in] x is the horizontal position in pixels (from the left edge)
+    /// @param[in] y is the vertical position in pixels (from the top edge)
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    RetCode_t SetTextCursor(loc_t x, loc_t y);
+
+    /// Get the current cursor position in pixels.
+    ///
+    /// @code
+    ///     point_t point = GetTextCursor();
+    ///     if (point.x > 100 && point.y > 150)
+    ///         //...
+    /// @endcode
+    ///
+    /// @returns cursor position.
+    ///
+    point_t GetTextCursor(void);
+    
+    /// Get the current cursor horizontal position in pixels.
+    ///
+    /// @returns cursor position horizontal offset.
+    ///
+    loc_t GetTextCursor_X(void);
+
+    /// Get the current cursor vertical position in pixels.
+    ///
+    /// @returns cursor position vertical offset.
+    ///
+    loc_t GetTextCursor_Y(void);
+
+    /// Configure additional Cursor Control settings.
+    ///
+    /// This API lets you modify other cursor control settings; 
+    /// Cursor visible/hidden, Cursor blink/normal, 
+    /// Cursor I-Beam/underscore/box.
+    ///
+    /// @param[in] cursor can be set to NOCURSOR (default), IBEAM,
+    ///         UNDER, or BLOCK.
+    /// @param[in] blink can be set to true or false (default false)
+    /// @returns success/failure code. @see RetCode_t
+    ///
+    RetCode_t SetTextCursorControl(cursor_t cursor = NOCURSOR, bool blink = false);
+    
+    /// Select the ISO 8859-X font to use next.
+    ///
+    /// Supported fonts: ISO 8859-1, -2, -3, -4
+    ///
+    /// @param[in] font selects the font for the subsequent text rendering.
+    ///
+    /// @note if either hScale or vScale is outside of its permitted range,
+    ///     the command is not executed.
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    RetCode_t SetTextFont(font_t font = ISO8859_1);
+    
+    /// Control the font behavior.
+    ///
+    /// This command lets you make several modifications to any text that
+    /// will be written to the screen.
+    ///
+    /// Options can be combined:
+    /// Default:
+    /// @li Full alignment disabled, 
+    /// @li Font with Background color, 
+    /// @li Font in normal orientiation,
+    /// @li Horizontal scale x 1
+    /// @li Vertical scale x 1
+    /// @li alignment
+    /// 
+    /// @param[in] fillit defaults to FILL, but can be NOFILL
+    /// @param[in] angle defaults to normal, but can be rotated
+    /// @param[in] hScale defaults to 1, but can be 1, 2, 3, or 4,
+    ///     and scales the font size by this amount.
+    /// @param[in] vScale defaults to 1, but can be 1, 2, 3, or 4,
+    ///     and scales the font size by this amount.
+    /// @param[in] alignment defaults to align_none, but can be
+    ///     align_full.
+    /// 
+    /// @note if either hScale or vScale is outside of its permitted range,
+    ///     the command is not executed.
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    RetCode_t SetTextFontControl(fill_t fillit = FILL, 
+        font_angle_t angle = normal, 
+        HorizontalScale hScale = 1, 
+        VerticalScale vScale = 1, 
+        alignment_t alignment = align_none);
+    
+    /// Control the font size
+    ///
+    /// This command lets you set the font enlargement for both horizontal
+    /// and vertical, independent of the rotation, background, and 
+    /// alignment. @see SetTextFontControl.
+    ///
+    /// @param[in] hScale defaults to 1, but can be 1, 2, 3, or 4,
+    ///     and scales the font size by this amount.
+    /// @param[in] vScale is an optional parameter that defaults to the hScale value, 
+    ///     but can be 1, 2, 3, or 4, and scales the font size by this amount.
+    ///
+    /// @code
+    ///     lcd.SetTextFontSize(2);     // Set the font to 2x normal size
+    ///     lcd.puts("Two times");
+    ///     lcd.SetTextFontSize(2,3);   // Set the font to 2x Width and 3x Height
+    ///     lcd.puts("2*2 3*h");
+    ///     lcd.SetTextFontSize();      // Restore to normal size in both dimensions
+    ///     lcd.puts("normal");
+    /// @endcode
+    ///
+    /// @note if either hScale or vScale is outside of its permitted range,
+    ///     the command is not executed.
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    RetCode_t SetTextFontSize(HorizontalScale hScale = 1, VerticalScale vScale = -1);
+    
+    /// put a character on the screen.
+    ///
+    /// @param[in] c is the character.
+    /// @returns the character, or EOF if there is an error.
+    ///
+    virtual int _putc(int c);
+
+    /// Write string of text to the display
+    ///
+    /// @code
+    ///     lcd.puts("Test STring");
+    /// @endcode
+    ///
+    /// @param[in] string is the null terminated string to send to the display.
+    ///
+    void puts(const char * string);
+    
+    /// Write string of text to the display at the specified location.
+    ///
+    /// @code
+    ///     lcd.puts(10,25, "Test STring");
+    /// @endcode
+    ///
+    /// @param[in] x is the horizontal position in pixels (from the left edge)
+    /// @param[in] y is the vertical position in pixels (from the top edge)
+    /// @param[in] string is the null terminated string to send to the display.
+    ///
+    void puts(loc_t x, loc_t y, const char * string);
+    
+    /// Prepare the controller to write binary data to the screen by positioning
+    /// the memory cursor.
+    ///
+    /// @param[in] x is the horizontal position in pixels (from the left edge)
+    /// @param[in] y is the vertical position in pixels (from the top edge)
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    virtual RetCode_t SetGraphicsCursor(loc_t x, loc_t y);
+    
+    /// Prepare the controller to read binary data from the screen by positioning
+    /// the memory read cursor.
+    ///
+    /// @param[in] x is the horizontal position in pixels (from the left edge)
+    /// @param[in] y is the vertical position in pixels (from the top edge)
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    virtual RetCode_t SetGraphicsCursorRead(loc_t x, loc_t y);
+    
+    /// Set the window, which controls where items are written to the screen.
+    ///
+    /// When something hits the window width, it wraps back to the left side
+    /// and down a row. If the initial write is outside the window, it will
+    /// be captured into the window when it crosses a boundary.
+    ///
+    /// @code
+    ///     lcd.window(10,10, 80,80);
+    ///     lcd.puts("012345678901234567890123456789012345678901234567890");
+    /// @endcode
+    ///
+    /// @param[in] x is the left edge in pixels.
+    /// @param[in] y is the top edge in pixels.
+    /// @param[in] width is the window width in pixels.
+    /// @param[in] height is the window height in pixels.
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    virtual RetCode_t window(loc_t x, loc_t y, dim_t width, dim_t height);
+    
+    /// Clear either the specified layer, or the active layer.
+    ///
+    /// The behavior is to clear the whole screen for the specified
+    /// layer. When not specified, the active drawing layer is cleared.
+    /// This command can also be used to specifically clear either,
+    /// or both layers. @see clsw().
+    ///
+    /// @code
+    ///     lcd.cls();
+    /// @endcode
+    ///
+    /// @param[in] layers is optional. If not provided, the active layer
+    ///     is cleared. If bit 0 is set, layer 0 is cleared, if bit
+    ///     1 is set, layer 1 is cleared. If both are set, both layers
+    ///     are cleared. Any other value does not cause an action.
+    ///     
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    virtual RetCode_t cls(uint16_t layers = 0);
+    
+    /// Clear the screen, or clear only the active window.
+    ///
+    /// The default behavior is to clear the whole screen. With the optional 
+    /// parameter, the action can be restricted to the active window, which
+    /// can be set with the @see window method.
+    ///
+    /// @code
+    ///     lcd.window(20,20, 40,10);
+    ///     lcd.clsw();
+    /// @endcode
+    ///
+    /// @param[in] region is an optional parameter that defaults to FULLWINDOW
+    ///         or may be set to ACTIVEWINDOW.
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    RetCode_t clsw(RA8875::Region_t region = FULLWINDOW);
+
+    /// Set the background color.
+    ///
+    /// @param[in] color is expressed in 16-bit format.
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    virtual RetCode_t background(color_t color);
+    
+    /// Set the background color.
+    ///
+    /// @param[in] r is the red element of the color.
+    /// @param[in] g is the green element of the color.
+    /// @param[in] b is the blue element of the color.
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    virtual RetCode_t background(unsigned char r, unsigned char g, unsigned char b);
+    
+    /// Set the foreground color.
+    ///
+    /// @param[in] color is expressed in 16-bit format.
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    virtual RetCode_t foreground(color_t color);
+    
+    /// Set the foreground color.
+    ///
+    /// @param[in] r is the red element of the color.
+    /// @param[in] g is the green element of the color.
+    /// @param[in] b is the blue element of the color.
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    virtual RetCode_t foreground(unsigned char r, unsigned char g, unsigned char b);
+    
+    /// Get the current foreground color value.
+    ///
+    /// @returns the current foreground color.
+    ///
+    color_t GetForeColor(void);
+        
+    /// Draw a pixel in the specified color.
+    ///
+    /// @note Unlike many other operations, this does not
+    ///         set the forecolor!
+    ///
+    /// @param[in] x is the horizontal offset to this pixel.
+    /// @param[in] y is the vertical offset to this pixel.
+    /// @param[in] color defines the color for the pixel.
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    virtual RetCode_t pixel(loc_t x, loc_t y, color_t color);
+    
+    /// Draw a pixel in the current foreground color.
+    ///
+    /// @param[in] x is the horizontal offset to this pixel.
+    /// @param[in] y is the veritical offset to this pixel.
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    virtual RetCode_t pixel(loc_t x, loc_t y);
+    
+    /// Get a pixel from the display.
+    ///
+    /// @param[in] x is the horizontal offset to this pixel.
+    /// @param[in] y is the vertical offset to this pixel.
+    /// @returns the pixel. see @color_t
+    ///
+    virtual color_t getPixel(loc_t x, loc_t y);
+    
+    /// Write a stream of pixels to the display.
+    ///
+    /// @param[in] p is a pointer to a color_t array to write.
+    /// @param[in] count is the number of pixels to write.
+    /// @param[in] x is the horizontal position on the display.
+    /// @param[in] y is the vertical position on the display.
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    virtual RetCode_t pixelStream(color_t * p, uint32_t count, loc_t x, loc_t y);
+    
+    /// Get a stream of pixels from the display.
+    ///
+    /// @param[in] p is a pointer to a color_t array to accept the stream.
+    /// @param[in] count is the number of pixels to read.
+    /// @param[in] x is the horizontal offset to this pixel.
+    /// @param[in] y is the vertical offset to this pixel.
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    virtual RetCode_t getPixelStream(color_t * p, uint32_t count, loc_t x, loc_t y);
+    
+    /// Draw a line in the specified color
+    ///
+    /// @note As a side effect, this changes the current
+    ///     foreground color for subsequent operations.
+    ///
+    /// @param[in] x1 is the horizontal start of the line.
+    /// @param[in] y1 is the vertical start of the line.
+    /// @param[in] x2 is the horizontal end of the line.
+    /// @param[in] y2 is the vertical end of the line.
+    /// @param[in] color defines the foreground color.
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    RetCode_t line(loc_t x1, loc_t y1, loc_t x2, loc_t y2, color_t color);
+
+    /// Draw a line
+    ///
+    /// Draws a line using the foreground color setting.
+    ///
+    /// @param[in] x1 is the horizontal start of the line.
+    /// @param[in] y1 is the vertical start of the line.
+    /// @param[in] x2 is the horizontal end of the line.
+    /// @param[in] y2 is the vertical end of the line.
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    RetCode_t line(loc_t x1, loc_t y1, loc_t x2, loc_t y2);
+
+    /// Draw a rectangle in the specified color
+    ///
+    /// @note As a side effect, this changes the current
+    ///     foreground color for subsequent operations.
+    ///
+    /// @param[in] rect defines the rectangle.
+    /// @param[in] color defines the foreground color.
+    /// @param[in] fillit is optional to FILL the rectangle. default is NOFILL.
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    RetCode_t rect(rect_t rect, color_t color, fill_t fillit);
+    
+     /// Draw a filled rectangle in the specified color
+    ///
+    /// @note As a side effect, this changes the current
+    ///     foreground color for subsequent operations.
+    ///
+    /// @param[in] rect defines the rectangle.
+    /// @param[in] color defines the foreground color.
+    /// @param[in] fillit is optional to FILL the rectangle. default is NOFILL.
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    RetCode_t fillrect(rect_t rect, color_t color, fill_t fillit = FILL);
+
+    /// Draw a rectangle in the specified color
+    ///
+    /// @note As a side effect, this changes the current
+    ///     foreground color for subsequent operations.
+    ///
+    /// @param[in] x1 is the horizontal start of the line.
+    /// @param[in] y1 is the vertical start of the line.
+    /// @param[in] x2 is the horizontal end of the line.
+    /// @param[in] y2 is the vertical end of the line.
+    /// @param[in] color defines the foreground color.
+    /// @param[in] fillit is optional to FILL the rectangle. default is FILL.
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    RetCode_t rect(loc_t x1, loc_t y1, loc_t x2, loc_t y2, 
+        color_t color, fill_t fillit = NOFILL);
+
+    /// Draw a filled rectangle in the specified color
+    ///
+    /// @note As a side effect, this changes the current
+    ///     foreground color for subsequent operations.
+    ///
+    /// @param[in] x1 is the horizontal start of the line.
+    /// @param[in] y1 is the vertical start of the line.
+    /// @param[in] x2 is the horizontal end of the line.
+    /// @param[in] y2 is the vertical end of the line.
+    /// @param[in] color defines the foreground color.
+    /// @param[in] fillit is optional to NOFILL the rectangle. default is FILL.
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    virtual RetCode_t fillrect(loc_t x1, loc_t y1, loc_t x2, loc_t y2, 
+        color_t color, fill_t fillit = FILL);
+
+    /// Draw a rectangle
+    ///
+    /// Draws a rectangle using the foreground color setting.
+    ///
+    /// @param[in] x1 is the horizontal start of the line.
+    /// @param[in] y1 is the vertical start of the line.
+    /// @param[in] x2 is the horizontal end of the line.
+    /// @param[in] y2 is the vertical end of the line.
+    /// @param[in] fillit is optional to FILL the rectangle. default is NOFILL.
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    RetCode_t rect(loc_t x1, loc_t y1, loc_t x2, loc_t y2, 
+        fill_t fillit = NOFILL);
+
+    /// Draw a filled rectangle with rounded corners using the specified color.
+    ///
+    /// This draws a rounded rectangle. A numbers of checks are made on the values,
+    /// and it could reduce this to drawing a line (if either x1 == x2, or y1 == y2),
+    /// or a single point (x1 == x2 && y1 == y2). If the radius parameters are
+    /// > 1/2 the length of that side (width or height), an error value is returned.
+    ///
+    /// @note As a side effect, this changes the current
+    ///     foreground color for subsequent operations.
+    ///
+    /// @param[in] x1 is the horizontal start of the line and must be <= x2.
+    /// @param[in] y1 is the vertical start of the line and must be <= y2.
+    /// @param[in] x2 is the horizontal end of the line and must be >= x1.
+    /// @param[in] y2 is the vertical end of the line and must be >= y1.
+    /// @param[in] radius1 defines the horizontal radius of the curved corner. Take care
+    ///         that this value < 1/2 the width of the rectangle, or bad_parameter 
+    ///         is returned.
+    /// @param[in] radius2 defines the vertical radius of the curved corner. Take care
+    ///         that this value < 1/2 the height of the rectangle, or bad_parameter 
+    ///         is returned.
+    /// @param[in] color defines the foreground color.
+    /// @param[in] fillit is optional to FILL the rectangle. default is NOFILL.
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    RetCode_t fillroundrect(loc_t x1, loc_t y1, loc_t x2, loc_t y2, 
+        dim_t radius1, dim_t radius2, color_t color, fill_t fillit = FILL);
+
+    /// Draw a rectangle with rounded corners using the specified color.
+    ///
+    /// This draws a rounded rectangle. A numbers of checks are made on the values,
+    /// and it could reduce this to drawing a line (if either x1 == x2, or y1 == y2),
+    /// or a single point (x1 == x2 && y1 == y2). If the radius parameters are
+    /// > 1/2 the length of that side (width or height), an error value is returned.
+    ///
+    /// @note As a side effect, this changes the current
+    ///     foreground color for subsequent operations.
+    ///
+    /// @param[in] x1 is the horizontal start of the line and must be <= x2.
+    /// @param[in] y1 is the vertical start of the line and must be <= y2.
+    /// @param[in] x2 is the horizontal end of the line and must be >= x1.
+    /// @param[in] y2 is the vertical end of the line and must be >= y1.
+    /// @param[in] radius1 defines the horizontal radius of the curved corner. Take care
+    ///         that this value < 1/2 the width of the rectangle, or bad_parameter 
+    ///         is returned.
+    /// @param[in] radius2 defines the vertical radius of the curved corner. Take care
+    ///         that this value < 1/2 the height of the rectangle, or bad_parameter 
+    ///         is returned.
+    /// @param[in] color defines the foreground color.
+    /// @param[in] fillit is optional to FILL the rectangle. default is NOFILL.
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    RetCode_t roundrect(loc_t x1, loc_t y1, loc_t x2, loc_t y2, 
+        dim_t radius1, dim_t radius2, color_t color, fill_t fillit = NOFILL);
+
+    /// Draw a rectangle with rounded corners.
+    ///
+    /// This draws a rounded rectangle. A numbers of checks are made on the values,
+    /// and it could reduce this to drawing a line (if either x1 == x2, or y1 == y2),
+    /// or a single point (x1 == x2 && y1 == y2). If the radius parameters are
+    /// > 1/2 the length of that side (width or height), an error value is returned.
+    ///
+    /// @param[in] x1 is the horizontal start of the line and must be <= x2.
+    /// @param[in] y1 is the vertical start of the line and must be <= y2.
+    /// @param[in] x2 is the horizontal end of the line and must be >= x1.
+    /// @param[in] y2 is the vertical end of the line and must be >= y1.
+    /// @param[in] radius1 defines the horizontal radius of the curved corner. Take care
+    ///         that this value < 1/2 the width of the rectangle, or bad_parameter 
+    ///         is returned.
+    /// @param[in] radius2 defines the vertical radius of the curved corner. Take care
+    ///         that this value < 1/2 the height of the rectangle, or bad_parameter 
+    ///         is returned.
+    /// @param[in] fillit is optional to FILL the rectangle. default is NOFILL.
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    RetCode_t roundrect(loc_t x1, loc_t y1, loc_t x2, loc_t y2, 
+        dim_t radius1, dim_t radius2, fill_t fillit = NOFILL);
+
+    /// Draw a triangle in the specified color.
+    ///
+    /// @note As a side effect, this changes the current
+    ///     foreground color for subsequent operations.
+    ///
+    /// @param[in] x1 is the horizontal for point 1.
+    /// @param[in] y1 is the vertical for point 1. 
+    /// @param[in] x2 is the horizontal for point 2.
+    /// @param[in] y2 is the vertical for point 2.
+    /// @param[in] x3 is the horizontal for point 3.
+    /// @param[in] y3 is the vertical for point 3.
+    /// @param[in] color defines the foreground color.
+    /// @param[in] fillit is optional to FILL the rectangle. default is NOFILL.
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    RetCode_t triangle(loc_t x1, loc_t y1, loc_t x2, loc_t y2, 
+        loc_t x3, loc_t y3, color_t color, fill_t fillit = NOFILL);
+    
+    /// Draw a filled triangle in the specified color.
+    ///
+    /// @note As a side effect, this changes the current
+    ///     foreground color for subsequent operations.
+    ///
+    /// @param[in] x1 is the horizontal for point 1.
+    /// @param[in] y1 is the vertical for point 1.
+    /// @param[in] x2 is the horizontal for point 2.
+    /// @param[in] y2 is the vertical for point 2.
+    /// @param[in] x3 is the horizontal for point 3.
+    /// @param[in] y3 is the vertical for point 3.
+    /// @param[in] color defines the foreground color.
+    /// @param[in] fillit is optional to FILL the rectangle. default is NOFILL.
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    RetCode_t filltriangle(loc_t x1, loc_t y1, loc_t x2, loc_t y2, 
+        loc_t x3, loc_t y3, color_t color, fill_t fillit = FILL);
+
+    /// Draw a triangle
+    ///
+    /// Draws a triangle using the foreground color setting.
+    ///
+    /// @param[in] x1 is the horizontal for point 1.
+    /// @param[in] y1 is the vertical for point 1.
+    /// @param[in] x2 is the horizontal for point 2.
+    /// @param[in] y2 is the vertical for point 2.
+    /// @param[in] x3 is the horizontal for point 3.
+    /// @param[in] y3 is the vertical for point 3.
+    /// @param[in] fillit is optional to FILL the rectangle. default is NOFILL.
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    RetCode_t triangle(loc_t x1, loc_t y1, loc_t x2, loc_t y2, 
+        loc_t x3, loc_t y3, fill_t fillit = NOFILL);
+    
+    /// Draw a circle using the specified color.
+    ///
+    /// @note As a side effect, this changes the current
+    ///     foreground color for subsequent operations.
+    ///
+    /// @param[in] x is the horizontal center of the circle.
+    /// @param[in] y is the vertical center of the circle.
+    /// @param[in] radius defines the size of the circle.
+    /// @param[in] color defines the foreground color.
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    RetCode_t circle(loc_t x, loc_t y, dim_t radius, color_t color, fill_t fillit = NOFILL);
+
+    /// Draw a filled circle using the specified color.
+    ///
+    /// @note As a side effect, this changes the current
+    ///     foreground color for subsequent operations.
+    ///
+    /// @param[in] x is the horizontal center of the circle.
+    /// @param[in] y is the vertical center of the circle.
+    /// @param[in] radius defines the size of the circle.
+    /// @param[in] color defines the foreground color.
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    RetCode_t fillcircle(loc_t x, loc_t y, dim_t radius, color_t color, fill_t fillit = FILL);
+
+    /// Draw a circle.
+    ///
+    /// Draws a circle using the foreground color setting.
+    ///
+    /// @param[in] x is the horizontal center of the circle.
+    /// @param[in] y is the vertical center of the circle.
+    /// @param[in] radius defines the size of the circle.
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    RetCode_t circle(loc_t x, loc_t y, dim_t radius, fill_t fillit = NOFILL);
+
+    /// Draw an Ellipse using the specified color
+    ///
+    /// @note As a side effect, this changes the current
+    ///     foreground color for subsequent operations.
+    ///
+    /// @param[in] x is the horizontal center of the ellipse.
+    /// @param[in] y is the vertical center of the ellipse.
+    /// @param[in] radius1 defines the horizontal radius of the ellipse.
+    /// @param[in] radius2 defines the vertical radius of the ellipse.
+    /// @param[in] color defines the foreground color.
+    /// @param[in] fillit defines whether the circle is filled or not.
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    RetCode_t ellipse(loc_t x, loc_t y, dim_t radius1, dim_t radius2, 
+        color_t color, fill_t fillit = NOFILL);
+
+    /// Draw a filled Ellipse using the specified color
+    ///
+    /// @note As a side effect, this changes the current
+    ///     foreground color for subsequent operations.
+    ///
+    /// @param[in] x is the horizontal center of the ellipse.
+    /// @param[in] y is the vertical center of the ellipse.
+    /// @param[in] radius1 defines the horizontal radius of the ellipse.
+    /// @param[in] radius2 defines the vertical radius of the ellipse.
+    /// @param[in] color defines the foreground color.
+    /// @param[in] fillit defines whether the circle is filled or not.
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    RetCode_t fillellipse(loc_t x, loc_t y, dim_t radius1, dim_t radius2, 
+        color_t color, fill_t fillit = FILL);
+
+    /// Draw an Ellipse
+    ///
+    /// Draws it using the foreground color setting.
+    ///
+    /// @param[in] x is the horizontal center of the ellipse.
+    /// @param[in] y is the vertical center of the ellipse.
+    /// @param[in] radius1 defines the horizontal radius of the ellipse.
+    /// @param[in] radius2 defines the vertical radius of the ellipse.
+    /// @param[in] fillit defines whether the circle is filled or not.
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    RetCode_t ellipse(loc_t x, loc_t y, dim_t radius1, dim_t radius2, fill_t fillit = NOFILL);
+    
+    /// Control display power
+    ///
+    /// @param[in] on when set to true will turn on the display, when false it is turned off.
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    RetCode_t Power(bool on);
+
+    /// Reset the display controller via the Software Reset interface.
+    ///
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    RetCode_t Reset(void);
+    
+    /// Set backlight brightness.
+    ///
+    /// When the built-in PWM is used to control the backlight, this 
+    /// API can be used to set the brightness.
+    /// 
+    /// @param[in] brightness ranges from 0 (off) to 255 (full on)
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    RetCode_t Backlight_u8(unsigned char brightness);
+    
+    /// Set backlight brightness.
+    ///
+    /// When the built-in PWM is used to control the backlight, this 
+    /// API can be used to set the brightness.
+    /// 
+    /// @param[in] brightness ranges from 0.0 (off) to 1.0 (full on)
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    RetCode_t Backlight(float brightness);
+
+    /// Select a bitmap font (provided by the user) for all subsequent text.
+    ///
+    /// @note Tool to create the fonts is accessible from its creator
+    ///     available at http://www.mikroe.com. 
+    ///     Change the data to an array of type char[].
+    ///
+    /// @param[in] font is a pointer to a specially formed font array.
+    ///     This special font array has a 4-byte header, followed by 
+    ///     the data:
+    ///   - the number of bytes per char
+    ///   - the vertical size in pixels for each character
+    ///   - the horizontal size in pixels for each character
+    ///   - the number of bytes per vertical line (width of the array)
+    /// @returns error code.
+    ///
+    virtual RetCode_t set_font(const unsigned char * font = NULL);
+
+    /// Get the RGB value for a DOS color.
+    ///
+    /// @param[in] i is the color, in the range 0 to 15;
+    /// @returns the RGB color of the selected index, or 0 
+    ///     if the index is out of bounds.
+    ///
+    color_t DOSColor(int i);
+
+    /// Get the color name (string) for a DOS color.
+    ///
+    /// @param[in] i is the color, in the range 0 to 15;
+    /// @returns a pointer to a string with the color name,
+    ///     or NULL if the index is out of bounds.
+    /// 
+    const char * DOSColorNames(int i);
+
+    /// Advanced method indicating the start of a graphics stream.
+    ///
+    /// This is called prior to a stream of pixel data being sent.
+    /// This may cause register configuration changes in the derived
+    /// class in order to prepare the hardware to accept the streaming
+    /// data.
+    ///
+    /// Following this command, a series of @see _putp() commands can
+    /// be used to send individual pixels to the screen.
+    ///
+    /// To conclude the graphics stream, @see _EndGraphicsStream should
+    /// be callled.
+    ///
+    /// @returns error code.
+    ///
+    virtual RetCode_t _StartGraphicsStream(void);
+    
+    /// Advanced method to put a single color pixel to the screen.
+    ///
+    /// This method may be called as many times as necessary after 
+    /// @see _StartGraphicsStream() is called, and it should be followed 
+    /// by _EndGraphicsStream.
+    ///
+    /// @param[in] pixel is a color value to be put on the screen.
+    /// @returns error code.
+    ///
+    virtual RetCode_t _putp(color_t pixel);
+    
+    /// Advanced method indicating the end of a graphics stream.
+    ///
+    /// This is called to conclude a stream of pixel data that was sent.
+    /// This may cause register configuration changes in the derived
+    /// class in order to stop the hardware from accept the streaming
+    /// data.
+    ///
+    /// @returns error code.
+    ///
+    virtual RetCode_t _EndGraphicsStream(void);
+
+    /// Set the SPI port frequency (in Hz).
+    ///
+    /// This uses the mbed SPI driver, and is therefore dependent on
+    /// its capabilities. The RA8875 can accept writes via SPI faster
+    /// than a read can be performed. The frequency set by this API
+    /// is for the SPI writes. It will automatically reduce the SPI
+    /// clock rate when a read is performed, and restore it for the 
+    /// next write. Alternately, the 2nd parameters permits setting
+    /// the read speed rather than letting it compute it automatically.
+    ///
+    /// @note The primary effect of this is to recover more CPU cycles
+    ///     for your application code. Keep in mind that when more than
+    ///     one command is sent to the display controller, that it
+    ///     will wait for the controller to finish the prior command.
+    ///     In this case, the performance is limited by the RA8875.
+    ///
+    /// @param[in] Hz is the frequency in Hz, tested range includes the
+    ///     range from 1,000,000 (1MHz) to 10,000,000 (10 MHz). Values
+    ///     outside this range will be accepted, but operation may
+    ///     be unreliable. This depends partially on your hardware design
+    ///     and the wires connecting the display module.
+    ///     The default value is 5,000,000, which should work for most
+    ///     applications as a starting point.
+    /// @param[in] Hz2 is an optional parameter and will set the read
+    ///     speed independently of the write speed.
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    RetCode_t frequency(unsigned long Hz = RA8875_DEFAULT_SPI_FREQ, unsigned long Hz2 = 0);
+    
+    /// This method captures the specified area as a 24-bit bitmap file.
+    ///
+    /// Even though this is a 16-bit display, the stored image is in
+    /// 24-bit format.
+    ///
+    /// This method will interrogate the current display setting and
+    /// create a bitmap based on those settings. For instance, if 
+    /// only layer 1 is visible, then the bitmap is only layer 1. However,
+    /// if there is some other operation in effect (transparent mode).
+    ///
+    /// @param[in] x is the left edge of the region to capture
+    /// @param[in] y is the top edge of the region to capture
+    /// @param[in] w is the width of the region to capture
+    /// @param[in] h is the height of the region to capture.
+    /// @param[out] Name_BMP is the filename to write the image to.
+    /// @return success or error code.
+    ///
+    RetCode_t PrintScreen(loc_t x, loc_t y, dim_t w, dim_t h, const char *Name_BMP);
+    
+    /// This method captures the specified area as a 24-bit bitmap file,
+    /// including the option of layer selection.
+    ///
+    /// @caution This method is deprecated as the alternate PrintScreen API
+    ///         automatically examines the display layer configuration.
+    ///         Therefore, calls to this API will ignore the layer parameter
+    ///         and automatically execute the other method.
+    ///
+    /// Even though this is a 16-bit display, the stored image is in
+    /// 24-bit format.
+    ///
+    /// @param[in] layer is 0 or 1 to select the layer to extract.
+    /// @param[in] x is the left edge of the region to capture
+    /// @param[in] y is the top edge of the region to capture
+    /// @param[in] w is the width of the region to capture
+    /// @param[in] h is the height of the region to capture.
+    /// @param[out] Name_BMP is the filename to write the image to.
+    /// @return success or error code.
+    ///
+    RetCode_t PrintScreen(uint16_t layer, loc_t x, loc_t y, dim_t w, dim_t h, const char *Name_BMP);
+    
+
+#ifdef PERF_METRICS
+    /// Clear the performance metrics to zero.
+    void ClearPerformance();
+    
+    /// Count idle time.
+    ///
+    /// @param[in] t is the amount of idle time to accumulate.
+    ///
+    void CountIdleTime(uint32_t t);
+    
+    /// Report the performance metrics for drawing functions using
+    /// the available serial channel.
+    ///
+    /// @param[in,out] pc is the serial channel to write to.
+    ///
+    void ReportPerformance(Serial & pc);
+#endif
+
+
+private:
+    /// Touch Panel register name definitions
+    #define TPCR0   0x70
+    #define TPCR1   0x71
+    #define TPXH    0x72
+    #define TPYH    0x73
+    #define TPXYL   0x74
+    #define INTC1   0xF0
+    #define INTC2   0xF1
+
+    /// Specify the default settings for the Touch Panel, where different from the chip defaults
+    #define TP_MODE_DEFAULT             TP_MODE_AUTO
+    #define TP_DEBOUNCE_DEFAULT         TP_DEBOUNCE_ON
+    #define TP_ADC_CLKDIV_DEFAULT       TP_ADC_CLKDIV_8
+
+    #define TP_ADC_SAMPLE_DEFAULT_CLKS  TP_ADC_SAMPLE_8192_CLKS
+
+    /// Other Touch Panel params
+    #define TPBUFSIZE   16       // Depth of the averaging buffers for x and y data
+
+    /// Touch Panel calibration matrix.
+    tpMatrix_t tpMatrix;
+
+    /// Internal function to put a character using the built-in (internal) font engine
+    ///
+    /// @param[in] is the character to put to the screen.
+    /// @returns the character put.
+    ///
+    int _internal_putc(int c);
+    
+    /// Internal function to put a character using the external font engine
+    ///
+    /// @param[in] is the character to put to the screen.
+    /// @returns the character put.
+    ///
+    int _external_putc(int c);
+    
+    /// Select the peripheral to use it.
+    ///
+    /// @param[in] chipsel when true will select the peripheral, and when false
+    ///     will deselect the chip. This is the logical selection, and
+    ///     the pin selection is the invert of this.
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    RetCode_t _select(bool chipsel);
+
+    /// Wait while the status register indicates the controller is busy.
+    ///
+    /// @param[in] mask is the mask of bits to monitor.
+    /// @returns true if a normal exit.
+    /// @returns false if a timeout exit.
+    ///
+    bool _WaitWhileBusy(uint8_t mask);
+
+    /// Wait while the the register anded with the mask is true.
+    ///
+    /// @param[in] reg is the register to monitor
+    /// @param[in] mask is the bit mask to monitor
+    /// @returns true if it was a normal exit
+    /// @returns false if it was a timeout that caused the exit.
+    ///
+    bool _WaitWhileReg(uint8_t reg, uint8_t mask);
+
+    /// set the spi port to either the write or the read speed.
+    ///
+    /// This is a private API used to toggle between the write
+    /// and the read speed for the SPI port to the RA8875, since
+    /// it can accept writes faster than reads.
+    ///
+    /// @param[in] writeSpeed when true selects the write frequency,
+    ///     and when false it selects the read frequency.
+    ///
+    void _setWriteSpeed(bool writeSpeed);
+
+    /// The most primitive - to write a data value to the SPI interface.
+    ///
+    /// @param[in] data is the value to write.
+    /// @returns a value read from the port, since SPI is often shift
+    ///     in while shifting out.
+    ///
+    unsigned char _spiwrite(unsigned char data);
+    
+    /// The most primitive - to read a data value to the SPI interface.
+    ///
+    /// This is really just a specialcase of the write command, where
+    /// the value zero is written in order to read.
+    ///
+    /// @returns a value read from the port, since SPI is often shift
+    ///     in while shifting out.
+    ///
+    unsigned char _spiread();
+    
+    const uint8_t * pKeyMap;
+    
+    SPI spi;                        ///< spi port
+    bool spiWriteSpeed;             ///< indicates if the current mode is write or read
+    unsigned long spiwritefreq;     ///< saved write freq
+    unsigned long spireadfreq;      ///< saved read freq
+    DigitalOut cs;                  ///< chip select pin, assumed active low
+    DigitalOut res;                 ///< reset pin, assumed active low
+    const unsigned char * font;     ///< reference to an external font somewhere in memory
+    loc_t cursor_x, cursor_y;    ///< used for external fonts only
+    
+    #ifdef PERF_METRICS
+    typedef enum
+    {
+        PRF_CLS,
+        PRF_DRAWPIXEL,
+        PRF_PIXELSTREAM,
+        PRF_READPIXEL,
+        PRF_READPIXELSTREAM,
+        PRF_DRAWLINE,
+        PRF_DRAWRECTANGLE,
+        PRF_DRAWROUNDEDRECTANGLE,
+        PRF_DRAWTRIANGLE,
+        PRF_DRAWCIRCLE,
+        PRF_DRAWELLIPSE,
+        METRICCOUNT
+    } method_e;
+    unsigned long metrics[METRICCOUNT];
+    unsigned long idletime_usec;
+    void RegisterPerformance(method_e method);
+    Timer performance;
+    #endif
+};
+
+//}     // namespace
+
+//using namespace SW_graphics;
+
+
+#ifdef TESTENABLE
+//      ______________  ______________  ______________  _______________
+//     /_____   _____/ /  ___________/ /  ___________/ /_____   ______/
+//          /  /      /  /            /  /                  /  /
+//         /  /      /  /___         /  /__________        /  /
+//        /  /      /  ____/        /__________   /       /  /
+//       /  /      /  /                       /  /       /  /
+//      /  /      /  /__________  ___________/  /       /  /
+//     /__/      /_____________/ /_____________/       /__/
+
+#include "WebColors.h"
+#include "Arial12x12.h"
+#include <algorithm>
+
+extern "C" void mbed_reset();
+
+/// This activates a small set of tests for the graphics library. 
+///
+/// Call this API and pass it the reference to the display class.
+/// It will then run a series of tests. It accepts interaction via
+/// stdin to switch from automatic test mode to manual, run a specific
+/// test, or to exit the test mode.
+///
+/// @param[in] lcd is a reference to the display class.
+/// @param[in] pc is a reference to a serial interface, typically the USB to PC.
+///
+void RunTestSet(RA8875 & lcd, Serial & pc);
+
+
+// To enable the test code, uncomment this section, or copy the
+// necessary pieces to your "main()".
+//
+// #include "mbed.h"
+// #include "RA8875.h"
+// RA8875 lcd(p5, p6, p7, p12, NC, "tft");    // MOSI, MISO, SCK, /ChipSelect, /reset, name
+// Serial pc(USBTX, USBRX);
+// extern "C" void mbed_reset();
+// int main()
+// {
+//     pc.baud(460800);    // I like a snappy terminal, so crank it up!
+//     pc.printf("\r\nRA8875 Test - Build " __DATE__ " " __TIME__ "\r\n");
+// 
+//     pc.printf("Turning on display\r\n");
+//     lcd.Reset();
+//     lcd.Power(true);  // display power is on, but the backlight is independent
+//     lcd.Backlight(0.5);
+//     RunTestSet(lcd, pc);
+// }
+
+#endif // TESTENABLE
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/RA8875/RA8875_Regs.h	Mon Nov 30 11:13:18 2015 +0000
@@ -0,0 +1,56 @@
+//
+// RA8875 Display Controller Register Definitions.
+//
+//
+#ifndef RA8875_REGS_H
+#define RA8875_REGS_H
+
+    // Touch Panel public macros
+    
+    /* Touch Panel Enable/Disable Reg TPCR0[7] */
+    #define TP_ENABLE   ((uint8_t)(1<<7))
+    #define TP_DISABLE  ((uint8_t)(0<<7))
+    
+    /* Touch Panel operating mode Reg TPCR1[6] */
+    #define TP_MODE_AUTO    ((uint8_t)(0<<6))   
+    #define TP_MODE_MANUAL  ((uint8_t)(1<<6))
+    
+    /* Touch Panel debounce Reg TPCR1[2]    */
+    #define TP_DEBOUNCE_OFF ((uint8_t)(0<<2))
+    #define TP_DEBOUNCE_ON  ((uint8_t)(1<<2))
+    
+    /* Touch Panel manual modes Reg TPCR1[1:0]  */
+    #define TP_MANUAL_IDLE      0
+    #define TP_MANUAL_WAIT      1
+    #define TP_MANUAL_LATCH_X   2
+    #define TP_MANUAL_LATCH_Y   3
+    
+    /* Touch Panel ADC Clock modes Reg TPCR0[2:0] */
+    #define TP_ADC_CLKDIV_1            0
+    #define TP_ADC_CLKDIV_2            1        
+    #define TP_ADC_CLKDIV_4            2        
+    #define TP_ADC_CLKDIV_8            3      
+    #define TP_ADC_CLKDIV_16           4        
+    #define TP_ADC_CLKDIV_32           5        
+    #define TP_ADC_CLKDIV_64           6        
+    #define TP_ADC_CLKDIV_128          7
+            
+    
+    /* Touch Panel Sample Time Reg TPCR0[6:4] */
+    #define TP_ADC_SAMPLE_512_CLKS     ((uint8_t)(0<<4))
+    #define TP_ADC_SAMPLE_1024_CLKS    ((uint8_t)(1<<4))
+    #define TP_ADC_SAMPLE_2048_CLKS    ((uint8_t)(2<<4))
+    #define TP_ADC_SAMPLE_4096_CLKS    ((uint8_t)(3<<4))
+    #define TP_ADC_SAMPLE_8192_CLKS    ((uint8_t)(4<<4))
+    #define TP_ADC_SAMPLE_16384_CLKS   ((uint8_t)(5<<4))
+    #define TP_ADC_SAMPLE_32768_CLKS   ((uint8_t)(6<<4))
+    #define TP_ADC_SAMPLE_65536_CLKS   ((uint8_t)(7<<4))
+    
+    /* RA8875 interrupt enable/flag/clear masks */
+    #define RA8875_INT_KEYSCAN          ((uint8_t)(1<<4))    /**< KEYSCAN interrupts  */
+    #define RA8875_INT_DMA              ((uint8_t)(1<<3))    /**< DMA interrupts  */
+    #define RA8875_INT_TP               ((uint8_t)(1<<2))    /**< Touch panel interrupts  */
+    #define RA8875_INT_BTE              ((uint8_t)(1<<1))    /**< BTE process complete interrupts  */
+    #define RA8875_INT_BTEMCU_FONTWR    ((uint8_t)(1<<0))    /**< BTE-MCU-R/W or Font-Write interrupts  */
+
+#endif // RA8875_REGS_H
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/RA8875/RA8875_Touch.cpp	Mon Nov 30 11:13:18 2015 +0000
@@ -0,0 +1,460 @@
+/// This file contains the RA8875 Touch panel methods.
+///
+
+#include "RA8875.h"
+
+// ### Touch Panel support code additions begin here
+
+RetCode_t RA8875::TouchPanelInit(void)
+{
+    //TPCR0: Set enable bit, default sample time, wakeup, and ADC clock
+    WriteCommand(TPCR0, TP_ENABLE | TP_ADC_SAMPLE_DEFAULT_CLKS | TP_ADC_CLKDIV_DEFAULT);
+    // TPCR1: Set auto/manual, Ref voltage, debounce, manual mode params
+    WriteCommand(TPCR1, TP_MODE_DEFAULT | TP_DEBOUNCE_DEFAULT);
+    WriteCommand(INTC1, ReadCommand(INTC1) | RA8875_INT_TP);        // reg INTC1: Enable Touch Panel Interrupts (D2 = 1)
+    WriteCommand(INTC2, RA8875_INT_TP);                            // reg INTC2: Clear any TP interrupt flag
+    return noerror;
+}
+
+RetCode_t RA8875::TouchPanelInit(uint8_t bTpEnable, uint8_t bTpAutoManual, uint8_t bTpDebounce, uint8_t bTpManualMode, uint8_t bTpAdcClkDiv, uint8_t bTpAdcSampleTime)
+{
+    // Parameter bounds check
+    if( \
+            !(bTpEnable == TP_ENABLE || bTpEnable == TP_ENABLE) || \
+            !(bTpAutoManual == TP_MODE_AUTO || bTpAutoManual == TP_MODE_MANUAL) || \
+            !(bTpDebounce == TP_DEBOUNCE_OFF || bTpDebounce == TP_DEBOUNCE_ON) || \
+            !(bTpManualMode <= TP_MANUAL_LATCH_Y) || \
+            !(bTpAdcClkDiv <= TP_ADC_CLKDIV_128) || \
+            !(bTpAdcSampleTime <= TP_ADC_SAMPLE_65536_CLKS) \
+      ) return bad_parameter;
+    // Construct the config byte for TPCR0 and write them
+    WriteCommand(TPCR0, bTpEnable | bTpAdcClkDiv | bTpAdcSampleTime);    // Note: Wakeup is never enabled
+    // Construct the config byte for TPCR1 and write them
+    WriteCommand(TPCR1, bTpManualMode | bTpDebounce | bTpManualMode);    // Note: Always uses internal Vref.
+    // Set up the interrupt flag and enable bits
+    WriteCommand(INTC1, ReadCommand(INTC1) | RA8875_INT_TP);        // reg INTC1: Enable Touch Panel Interrupts (D2 = 1)
+    WriteCommand(INTC2, RA8875_INT_TP);                            // reg INTC2: Clear any TP interrupt flag
+    return noerror;
+}
+
+    // +----------------------------------------------------+
+    // |                                                    |
+    // |  1                                                 |
+    // |                                                    |
+    // |                                                    |
+    // |                                               2    |
+    // |                                                    |
+    // |                                                    |
+    // |                         3                          |
+    // |                                                    |
+    // +----------------------------------------------------+
+
+
+RetCode_t RA8875::TouchPanelCalibrate(tpMatrix_t * matrix)
+{
+    return TouchPanelCalibrate(NULL, matrix);
+}
+
+
+RetCode_t RA8875::TouchPanelCalibrate(const char * msg, tpMatrix_t * matrix)
+{
+    point_t pTest[3];
+    point_t pSample[3];
+    loc_t x,y;
+    
+    cls();
+    if (msg)
+        puts(msg);
+    SetTextCursor(0,height()/2);
+    pTest[0].x = 50;            pTest[0].y = 50;
+    pTest[1].x = width() - 50;  pTest[1].y = height()/2;
+    pTest[2].x = width()/2;     pTest[2].y = height() - 50;
+    for (int i=0; i<3; i++) {
+        foreground(Blue);
+        printf(" (%3d,%3d) => ", pTest[i].x, pTest[i].y);
+        line(pTest[i].x-10, pTest[i].y, pTest[i].x+10, pTest[i].y, White);
+        line(pTest[i].x, pTest[i].y-10, pTest[i].x, pTest[i].y+10, White);
+        while (!TouchPanelA2DFiltered(&x, &y))
+            wait_ms(20);
+        pSample[i].x = x;
+        pSample[i].y = y;
+        line(pTest[i].x-10, pTest[i].y, pTest[i].x+10, pTest[i].y, Black);
+        line(pTest[i].x, pTest[i].y-10, pTest[i].x, pTest[i].y+10, Black);
+        foreground(Blue);
+        printf(" (%4d,%4d)\r\n", x,y);
+        while (TouchPanelA2DFiltered(&x, &y))
+            wait_ms(20);
+        wait(2);
+    }
+    return TouchPanelComputeCalibration(pTest, pSample, matrix);
+}
+
+
+/**********************************************************************
+ *
+ *     Function: getDisplayPoint()
+ *
+ *  Description: Given a valid set of calibration factors and a point
+ *                value reported by the touch screen, this function
+ *                calculates and returns the true (or closest to true)
+ *                display point below the spot where the touch screen 
+ *                was touched.
+ * 
+ *
+ * 
+ *  Argument(s): displayPtr (output) - Pointer to the calculated
+ *                                      (true) display point.
+ *               screenPtr (input) - Pointer to the reported touch
+ *                                    screen point.
+ *               matrixPtr (input) - Pointer to calibration factors
+ *                                    matrix previously calculated
+ *                                    from a call to 
+ *                                    setCalibrationMatrix()
+ * 
+ *
+ *  The function simply solves for Xd and Yd by implementing the 
+ *   computations required by the translation matrix.  
+ * 
+ *                                              /-     -\
+ *              /-    -\     /-            -\   |       |
+ *              |      |     |              |   |   Xs  |
+ *              |  Xd  |     | A    B    C  |   |       |
+ *              |      |  =  |              | * |   Ys  |
+ *              |  Yd  |     | D    E    F  |   |       |
+ *              |      |     |              |   |   1   |
+ *              \-    -/     \-            -/   |       |
+ *                                              \-     -/
+ * 
+ *  It must be kept brief to avoid consuming CPU cycles.
+ *
+ *       Return: OK - the display point was correctly calculated 
+ *                     and its value is in the output argument.
+ *               NOT_OK - an error was detected and the function
+ *                         failed to return a valid point.
+ *
+ *                 NOTE!    NOTE!    NOTE!
+ *
+ *  setCalibrationMatrix() and getDisplayPoint() will do fine
+ *  for you as they are, provided that your digitizer         
+ *  resolution does not exceed 10 bits (1024 values).  Higher
+ *  resolutions may cause the integer operations to overflow
+ *  and return incorrect values.  If you wish to use these   
+ *  functions with digitizer resolutions of 12 bits (4096    
+ *  values) you will either have to a) use 64-bit signed     
+ *  integer variables and math, or b) judiciously modify the 
+ *  operations to scale results by a factor of 2 or even 4.  
+ *
+ */
+bool RA8875::TouchPanelReadable(point_t * TouchPoint)
+{
+    bool touched = false;
+    point_t screenpoint = {0, 0};
+    
+    if (TouchPanelA2DFiltered(&screenpoint.x, &screenpoint.y)) {
+        touched = true;
+        if (tpMatrix.Divider != 0 && TouchPoint) {
+            /* Operation order is important since we are doing integer */
+            /*  math. Make sure you add all terms together before      */
+            /*  dividing, so that the remainder is not rounded off     */
+            /*  prematurely.                                           */
+            TouchPoint->x = ( (tpMatrix.An * screenpoint.x) +
+                              (tpMatrix.Bn * screenpoint.y) +
+                              tpMatrix.Cn
+                            ) / tpMatrix.Divider ;
+
+            TouchPoint->y = ( (tpMatrix.Dn * screenpoint.x) +
+                              (tpMatrix.En * screenpoint.y) +
+                              tpMatrix.Fn
+                            ) / tpMatrix.Divider ;
+        } else {
+            touched = false;
+        }
+    }
+    return touched;
+}
+
+
+RetCode_t RA8875::TouchPanelSetMatrix(tpMatrix_t * matrixPtr)
+{
+    if (matrixPtr == NULL || matrixPtr->Divider == 0)
+        return bad_parameter;
+    memcpy(&tpMatrix, matrixPtr, sizeof(tpMatrix_t));
+    return noerror;
+}
+
+
+bool RA8875::TouchPanelA2DFiltered(loc_t *x, loc_t *y)
+{
+    unsigned char touchready;
+    static int xbuf[TPBUFSIZE], ybuf[TPBUFSIZE], sample = 0;
+    int i, j, temp;
+
+    if( (ReadCommand(INTC2) & RA8875_INT_TP) ) {        // Test for TP Interrupt pending in register INTC2
+        // Get the next data samples
+        ybuf[sample] =  ReadCommand(TPYH) << 2 | ( (ReadCommand(TPXYL) & 0xC) >> 2 );   // D[9:2] from reg TPYH, D[1:0] from reg TPXYL[3:2]
+        xbuf[sample] =  ReadCommand(TPXH) << 2 | ( (ReadCommand(TPXYL) & 0x3)      );   // D[9:2] from reg TPXH, D[1:0] from reg TPXYL[1:0]
+        // Check for a complete set
+        if(++sample == TPBUFSIZE) {
+            // Buffers are full, so process them using Finn's method described in Analog Dialogue No. 44, Feb 2010
+            // This requires sorting the samples in order of size, then discarding the top 25% and
+            //   bottom 25% as noise spikes. Finally, the middle 50% of the values are averaged to
+            //   reduce Gaussian noise.
+
+            // Sort the Y buffer using an Insertion Sort
+            for(i = 1; i <= TPBUFSIZE; i++) {
+                temp = ybuf[i];
+                j = i;
+                while( j && (ybuf[j-1] > temp) ) {
+                    ybuf[j] = ybuf[j-1];
+                    j = j-1;
+                }
+                ybuf[j] = temp;
+            } // End of Y sort
+            // Sort the X buffer the same way
+            for(i = 1; i <= TPBUFSIZE; i++) {
+                temp = xbuf[i];
+                j = i;
+                while( j && (xbuf[j-1] > temp) ) {
+                    xbuf[j] = xbuf[j-1];
+                    j = j-1;
+                }
+                xbuf[j] = temp;
+            } // End of X sort
+            // Average the middle half of the  Y values and report them
+            j = 0;
+            for(i = (TPBUFSIZE/4) - 1; i < TPBUFSIZE - TPBUFSIZE/4; i++ ) {
+                j += ybuf[i];
+            }
+            *y = j * (float)2/TPBUFSIZE;    // This is the average
+            // Average the middle half of the  X values and report them
+            j = 0;
+            for(i = (TPBUFSIZE/4) - 1; i < TPBUFSIZE - TPBUFSIZE/4; i++ ) {
+                j += xbuf[i];
+            }
+            *x = j * (float)2/TPBUFSIZE;    // This is the average
+            // Tidy up and return
+            touchready = 1;
+            sample = 0;             // Ready to start on the next set of data samples
+        } else {
+            // Buffer not yet full, so do not return any results yet
+            touchready = 0;
+        }
+        WriteCommand(INTC2, RA8875_INT_TP);            // reg INTC2: Clear that TP interrupt flag
+    } // End of initial if -- data has been read and processed
+    else
+        touchready = 0;         // Touch Panel "Int" was not set
+    return touchready;
+}
+
+bool RA8875::TouchPanelA2DRaw(loc_t *x, loc_t *y)
+{
+    unsigned char touchready;
+
+    if( (ReadCommand(INTC2) & RA8875_INT_TP) ) {        // Test for TP Interrupt pending in register INTC2
+        *y =  ReadCommand(TPYH) << 2 | ( (ReadCommand(TPXYL) & 0xC) >> 2 );   // D[9:2] from reg TPYH, D[1:0] from reg TPXYL[3:2]
+        *x =  ReadCommand(TPXH) << 2 | ( (ReadCommand(TPXYL) & 0x3)      );   // D[9:2] from reg TPXH, D[1:0] from reg TPXYL[1:0]
+        WriteCommand(INTC2, RA8875_INT_TP);            // reg INTC2: Clear that TP interrupt flag
+        touchready = 1;
+    } else
+        touchready = 0;
+    return touchready;
+}
+
+/*   The following section is derived from Carlos E. Vidales.
+ *
+ *   Copyright (c) 2001, Carlos E. Vidales. All rights reserved.
+ *
+ *   This sample program was written and put in the public domain 
+ *    by Carlos E. Vidales.  The program is provided "as is" 
+ *    without warranty of any kind, either expressed or implied.
+ *   If you choose to use the program within your own products
+ *    you do so at your own risk, and assume the responsibility
+ *    for servicing, repairing or correcting the program should
+ *    it prove defective in any manner.
+ *   You may copy and distribute the program's source code in any 
+ *    medium, provided that you also include in each copy an
+ *    appropriate copyright notice and disclaimer of warranty.
+ *   You may also modify this program and distribute copies of
+ *    it provided that you include prominent notices stating 
+ *    that you changed the file(s) and the date of any change,
+ *    and that you do not charge any royalties or licenses for 
+ *    its use.
+ * 
+ *   This file contains functions that implement calculations 
+ *    necessary to obtain calibration factors for a touch screen
+ *    that suffers from multiple distortion effects: namely, 
+ *    translation, scaling and rotation.
+ *
+ *   The following set of equations represent a valid display 
+ *    point given a corresponding set of touch screen points:
+ *
+ *                                              /-     -\
+ *              /-    -\     /-            -\   |       |
+ *              |      |     |              |   |   Xs  |
+ *              |  Xd  |     | A    B    C  |   |       |
+ *              |      |  =  |              | * |   Ys  |
+ *              |  Yd  |     | D    E    F  |   |       |
+ *              |      |     |              |   |   1   |
+ *              \-    -/     \-            -/   |       |
+ *                                              \-     -/
+ *    where:
+ *           (Xd,Yd) represents the desired display point 
+ *                    coordinates,
+ *           (Xs,Ys) represents the available touch screen
+ *                    coordinates, and the matrix
+ *           /-   -\
+ *           |A,B,C|
+ *           |D,E,F| represents the factors used to translate
+ *           \-   -/  the available touch screen point values
+ *                    into the corresponding display 
+ *                    coordinates.
+ *    Note that for practical considerations, the utilities 
+ *     within this file do not use the matrix coefficients as
+ *     defined above, but instead use the following 
+ *     equivalents, since floating point math is not used:
+ *            A = An/Divider 
+ *            B = Bn/Divider 
+ *            C = Cn/Divider 
+ *            D = Dn/Divider 
+ *            E = En/Divider 
+ *            F = Fn/Divider 
+ *    The functions provided within this file are:
+ *          setCalibrationMatrix() - calculates the set of factors
+ *                                    in the above equation, given
+ *                                    three sets of test points.
+ *               getDisplayPoint() - returns the actual display
+ *                                    coordinates, given a set of
+ *                                    touch screen coordinates.
+ * translateRawScreenCoordinates() - helper function to transform
+ *                                    raw screen points into values
+ *                                    scaled to the desired display
+ *                                    resolution.
+ */
+
+/**********************************************************************
+ *
+ *     Function: setCalibrationMatrix()
+ *
+ *  Description: Calling this function with valid input data
+ *                in the display and screen input arguments 
+ *                causes the calibration factors between the
+ *                screen and display points to be calculated,
+ *                and the output argument - matrixPtr - to be 
+ *                populated.
+ *
+ *               This function needs to be called only when new
+ *                calibration factors are desired.
+ *               
+ *  
+ *  Argument(s): displayPtr (input) - Pointer to an array of three 
+ *                                     sample, reference points.
+ *               screenPtr (input) - Pointer to the array of touch 
+ *                                    screen points corresponding 
+ *                                    to the reference display points.
+ *               matrixPtr (output) - Pointer to the calibration 
+ *                                     matrix computed for the set 
+ *                                     of points being provided.
+ *
+ *
+ *  From the article text, recall that the matrix coefficients are
+ *   resolved to be the following:
+ *
+ *
+ *      Divider =  (Xs0 - Xs2)*(Ys1 - Ys2) - (Xs1 - Xs2)*(Ys0 - Ys2)
+ *
+ *
+ *
+ *                 (Xd0 - Xd2)*(Ys1 - Ys2) - (Xd1 - Xd2)*(Ys0 - Ys2)
+ *            A = ---------------------------------------------------
+ *                                   Divider
+ *
+ *
+ *                 (Xs0 - Xs2)*(Xd1 - Xd2) - (Xd0 - Xd2)*(Xs1 - Xs2)
+ *            B = ---------------------------------------------------
+ *                                   Divider
+ *
+ *
+ *                 Ys0*(Xs2*Xd1 - Xs1*Xd2) + 
+ *                             Ys1*(Xs0*Xd2 - Xs2*Xd0) + 
+ *                                           Ys2*(Xs1*Xd0 - Xs0*Xd1)
+ *            C = ---------------------------------------------------
+ *                                   Divider
+ *
+ *
+ *                 (Yd0 - Yd2)*(Ys1 - Ys2) - (Yd1 - Yd2)*(Ys0 - Ys2)
+ *            D = ---------------------------------------------------
+ *                                   Divider
+ *
+ *
+ *                 (Xs0 - Xs2)*(Yd1 - Yd2) - (Yd0 - Yd2)*(Xs1 - Xs2)
+ *            E = ---------------------------------------------------
+ *                                   Divider
+ *
+ *
+ *                 Ys0*(Xs2*Yd1 - Xs1*Yd2) + 
+ *                             Ys1*(Xs0*Yd2 - Xs2*Yd0) + 
+ *                                           Ys2*(Xs1*Yd0 - Xs0*Yd1)
+ *            F = ---------------------------------------------------
+ *                                   Divider
+ *
+ *
+ *       Return: OK - the calibration matrix was correctly 
+ *                     calculated and its value is in the 
+ *                     output argument.
+ *               NOT_OK - an error was detected and the 
+ *                         function failed to return a valid
+ *                         set of matrix values.
+ *                        The only time this sample code returns
+ *                        NOT_OK is when Divider == 0
+ *
+ *
+ *
+ *                 NOTE!    NOTE!    NOTE!
+ *
+ *  setCalibrationMatrix() and getDisplayPoint() will do fine
+ *  for you as they are, provided that your digitizer         
+ *  resolution does not exceed 10 bits (1024 values).  Higher
+ *  resolutions may cause the integer operations to overflow
+ *  and return incorrect values.  If you wish to use these   
+ *  functions with digitizer resolutions of 12 bits (4096    
+ *  values) you will either have to a) use 64-bit signed     
+ *  integer variables and math, or b) judiciously modify the 
+ *  operations to scale results by a factor of 2 or even 4.  
+ *
+ */
+RetCode_t RA8875::TouchPanelComputeCalibration(point_t * displayPtr, point_t * screenPtr, tpMatrix_t * matrixPtr)
+{
+    RetCode_t retValue = noerror;
+
+    tpMatrix.Divider = ((screenPtr[0].x - screenPtr[2].x) * (screenPtr[1].y - screenPtr[2].y)) -
+                       ((screenPtr[1].x - screenPtr[2].x) * (screenPtr[0].y - screenPtr[2].y)) ;
+
+    if( tpMatrix.Divider == 0 )  {
+        retValue = bad_parameter;
+    }  else   {
+        tpMatrix.An = ((displayPtr[0].x - displayPtr[2].x) * (screenPtr[1].y - screenPtr[2].y)) -
+                      ((displayPtr[1].x - displayPtr[2].x) * (screenPtr[0].y - screenPtr[2].y)) ;
+
+        tpMatrix.Bn = ((screenPtr[0].x - screenPtr[2].x) * (displayPtr[1].x - displayPtr[2].x)) -
+                      ((displayPtr[0].x - displayPtr[2].x) * (screenPtr[1].x - screenPtr[2].x)) ;
+
+        tpMatrix.Cn = (screenPtr[2].x * displayPtr[1].x - screenPtr[1].x * displayPtr[2].x) * screenPtr[0].y +
+                      (screenPtr[0].x * displayPtr[2].x - screenPtr[2].x * displayPtr[0].x) * screenPtr[1].y +
+                      (screenPtr[1].x * displayPtr[0].x - screenPtr[0].x * displayPtr[1].x) * screenPtr[2].y ;
+
+        tpMatrix.Dn = ((displayPtr[0].y - displayPtr[2].y) * (screenPtr[1].y - screenPtr[2].y)) -
+                      ((displayPtr[1].y - displayPtr[2].y) * (screenPtr[0].y - screenPtr[2].y)) ;
+
+        tpMatrix.En = ((screenPtr[0].x - screenPtr[2].x) * (displayPtr[1].y - displayPtr[2].y)) -
+                      ((displayPtr[0].y - displayPtr[2].y) * (screenPtr[1].x - screenPtr[2].x)) ;
+
+        tpMatrix.Fn = (screenPtr[2].x * displayPtr[1].y - screenPtr[1].x * displayPtr[2].y) * screenPtr[0].y +
+                      (screenPtr[0].x * displayPtr[2].y - screenPtr[2].x * displayPtr[0].y) * screenPtr[1].y +
+                      (screenPtr[1].x * displayPtr[0].y - screenPtr[0].x * displayPtr[1].y) * screenPtr[2].y ;
+        if (matrixPtr)
+            memcpy(matrixPtr, &tpMatrix, sizeof(tpMatrix_t));
+    }
+    return( retValue ) ;
+}
+
+// #### end of touch panel code additions
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/RA8875/Small_6.h	Mon Nov 30 11:13:18 2015 +0000
@@ -0,0 +1,105 @@
+
+#ifndef SMALL_6_H
+#define SMALL_6_H
+
+const unsigned char Small_6[] = {
+    9,8,8,1,                                    // Length,horz,vert,byte/vert
+    0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char  
+    0x02, 0x00, 0x2F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char !
+    0x04, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,  // Code for char "
+    0x06, 0x00, 0x12, 0x3F, 0x12, 0x3F, 0x12, 0x00, 0x00,  // Code for char #
+    0x04, 0x00, 0x26, 0x7F, 0x32, 0x00, 0x00, 0x00, 0x00,  // Code for char $
+    0x05, 0x00, 0x13, 0x0B, 0x34, 0x32, 0x00, 0x00, 0x00,  // Code for char %
+    0x05, 0x00, 0x1A, 0x25, 0x1A, 0x28, 0x00, 0x00, 0x00,  // Code for char &
+    0x02, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char '
+    0x03, 0x00, 0x7E, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char (
+    0x03, 0x00, 0x81, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char )
+    0x03, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char *
+    0x04, 0x00, 0x08, 0x1C, 0x08, 0x00, 0x00, 0x00, 0x00,  // Code for char +
+    0x02, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char ,
+    0x03, 0x00, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char -
+    0x02, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char .
+    0x03, 0x00, 0x38, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char /
+    0x05, 0x00, 0x1E, 0x21, 0x21, 0x1E, 0x00, 0x00, 0x00,  // Code for char 0
+    0x05, 0x00, 0x02, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char 1
+    0x05, 0x00, 0x32, 0x29, 0x29, 0x26, 0x00, 0x00, 0x00,  // Code for char 2
+    0x05, 0x00, 0x12, 0x21, 0x25, 0x1A, 0x00, 0x00, 0x00,  // Code for char 3
+    0x05, 0x00, 0x18, 0x16, 0x3F, 0x10, 0x00, 0x00, 0x00,  // Code for char 4
+    0x05, 0x00, 0x27, 0x25, 0x19, 0x00, 0x00, 0x00, 0x00,  // Code for char 5
+    0x05, 0x00, 0x1E, 0x25, 0x25, 0x18, 0x00, 0x00, 0x00,  // Code for char 6
+    0x05, 0x00, 0x01, 0x3D, 0x03, 0x00, 0x00, 0x00, 0x00,  // Code for char 7
+    0x05, 0x00, 0x1A, 0x25, 0x25, 0x1A, 0x00, 0x00, 0x00,  // Code for char 8
+    0x05, 0x00, 0x12, 0x25, 0x25, 0x1E, 0x00, 0x00, 0x00,  // Code for char 9
+    0x02, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char :
+    0x02, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char ;
+    0x04, 0x00, 0x08, 0x14, 0x22, 0x00, 0x00, 0x00, 0x00,  // Code for char <
+    0x04, 0x00, 0x14, 0x14, 0x14, 0x00, 0x00, 0x00, 0x00,  // Code for char =
+    0x04, 0x00, 0x22, 0x14, 0x08, 0x00, 0x00, 0x00, 0x00,  // Code for char >
+    0x05, 0x00, 0x02, 0x29, 0x05, 0x02, 0x00, 0x00, 0x00,  // Code for char ?
+    0x08, 0x00, 0x1C, 0x22, 0x49, 0x55, 0x59, 0x12, 0x0C,  // Code for char @
+    0x06, 0x00, 0x30, 0x0C, 0x0B, 0x0C, 0x30, 0x00, 0x00,  // Code for char A
+    0x06, 0x00, 0x3F, 0x25, 0x25, 0x25, 0x1A, 0x00, 0x00,  // Code for char B
+    0x06, 0x00, 0x1E, 0x21, 0x21, 0x21, 0x12, 0x00, 0x00,  // Code for char C
+    0x06, 0x00, 0x3F, 0x21, 0x21, 0x21, 0x1E, 0x00, 0x00,  // Code for char D
+    0x05, 0x00, 0x3F, 0x25, 0x25, 0x21, 0x00, 0x00, 0x00,  // Code for char E
+    0x05, 0x00, 0x3F, 0x05, 0x05, 0x01, 0x00, 0x00, 0x00,  // Code for char F
+    0x06, 0x00, 0x1E, 0x21, 0x21, 0x29, 0x3A, 0x00, 0x00,  // Code for char G
+    0x05, 0x00, 0x3F, 0x04, 0x04, 0x3F, 0x00, 0x00, 0x00,  // Code for char H
+    0x02, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char I
+    0x04, 0x00, 0x30, 0x20, 0x1F, 0x00, 0x00, 0x00, 0x00,  // Code for char J
+    0x05, 0x00, 0x3F, 0x0C, 0x12, 0x21, 0x00, 0x00, 0x00,  // Code for char K
+    0x04, 0x00, 0x3F, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00,  // Code for char L
+    0x08, 0x00, 0x3F, 0x03, 0x0C, 0x30, 0x0C, 0x03, 0x3F,  // Code for char M
+    0x06, 0x00, 0x3F, 0x03, 0x0C, 0x30, 0x3F, 0x00, 0x00,  // Code for char N
+    0x06, 0x00, 0x1E, 0x21, 0x21, 0x21, 0x1E, 0x00, 0x00,  // Code for char O
+    0x05, 0x00, 0x3F, 0x09, 0x09, 0x06, 0x00, 0x00, 0x00,  // Code for char P
+    0x06, 0x00, 0x1E, 0x21, 0x29, 0x11, 0x2E, 0x00, 0x00,  // Code for char Q
+    0x06, 0x00, 0x3F, 0x09, 0x09, 0x09, 0x36, 0x00, 0x00,  // Code for char R
+    0x05, 0x00, 0x12, 0x25, 0x29, 0x12, 0x00, 0x00, 0x00,  // Code for char S
+    0x06, 0x00, 0x01, 0x01, 0x3F, 0x01, 0x01, 0x00, 0x00,  // Code for char T
+    0x06, 0x00, 0x1F, 0x20, 0x20, 0x20, 0x1F, 0x00, 0x00,  // Code for char U
+    0x06, 0x00, 0x03, 0x0C, 0x30, 0x0C, 0x03, 0x00, 0x00,  // Code for char V
+    0x08, 0x00, 0x03, 0x0C, 0x30, 0x0C, 0x30, 0x0C, 0x03,  // Code for char W
+    0x06, 0x00, 0x21, 0x12, 0x0C, 0x12, 0x21, 0x00, 0x00,  // Code for char X
+    0x06, 0x00, 0x01, 0x02, 0x3C, 0x02, 0x01, 0x00, 0x00,  // Code for char Y
+    0x05, 0x00, 0x31, 0x29, 0x25, 0x23, 0x00, 0x00, 0x00,  // Code for char Z
+    0x03, 0x00, 0x7F, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char [
+    0x03, 0x00, 0x07, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char BackSlash
+    0x03, 0x00, 0x41, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char ]
+    0x04, 0x00, 0x02, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00,  // Code for char ^
+    0x05, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00,  // Code for char _
+    0x03, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char `
+    0x04, 0x00, 0x14, 0x24, 0x38, 0x00, 0x00, 0x00, 0x00,  // Code for char a
+    0x05, 0x00, 0x3F, 0x24, 0x24, 0x18, 0x00, 0x00, 0x00,  // Code for char b
+    0x04, 0x00, 0x18, 0x24, 0x24, 0x00, 0x00, 0x00, 0x00,  // Code for char c
+    0x05, 0x00, 0x18, 0x24, 0x24, 0x3F, 0x00, 0x00, 0x00,  // Code for char d
+    0x04, 0x00, 0x18, 0x34, 0x28, 0x00, 0x00, 0x00, 0x00,  // Code for char e
+    0x03, 0x00, 0x3E, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char f
+    0x05, 0x00, 0x18, 0xA4, 0xA4, 0x7C, 0x00, 0x00, 0x00,  // Code for char g
+    0x04, 0x00, 0x3F, 0x04, 0x38, 0x00, 0x00, 0x00, 0x00,  // Code for char h
+    0x02, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char i
+    0x02, 0x00, 0xFD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char j
+    0x04, 0x00, 0x3F, 0x08, 0x34, 0x00, 0x00, 0x00, 0x00,  // Code for char k
+    0x02, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char l
+    0x06, 0x00, 0x3C, 0x04, 0x3C, 0x04, 0x38, 0x00, 0x00,  // Code for char m
+    0x04, 0x00, 0x3C, 0x04, 0x38, 0x00, 0x00, 0x00, 0x00,  // Code for char n
+    0x05, 0x00, 0x18, 0x24, 0x24, 0x18, 0x00, 0x00, 0x00,  // Code for char o
+    0x05, 0x00, 0xFC, 0x24, 0x24, 0x18, 0x00, 0x00, 0x00,  // Code for char p
+    0x05, 0x00, 0x18, 0x24, 0x24, 0xFC, 0x00, 0x00, 0x00,  // Code for char q
+    0x03, 0x00, 0x3C, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char r
+    0x04, 0x00, 0x28, 0x24, 0x14, 0x00, 0x00, 0x00, 0x00,  // Code for char s
+    0x03, 0x00, 0x1E, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char t
+    0x04, 0x00, 0x1C, 0x20, 0x3C, 0x00, 0x00, 0x00, 0x00,  // Code for char u
+    0x04, 0x00, 0x0C, 0x30, 0x0C, 0x00, 0x00, 0x00, 0x00,  // Code for char v
+    0x06, 0x00, 0x0C, 0x30, 0x0C, 0x30, 0x0C, 0x00, 0x00,  // Code for char w
+    0x04, 0x00, 0x24, 0x18, 0x24, 0x00, 0x00, 0x00, 0x00,  // Code for char x
+    0x04, 0x00, 0x9C, 0x60, 0x1C, 0x00, 0x00, 0x00, 0x00,  // Code for char y
+    0x04, 0x00, 0x34, 0x24, 0x2C, 0x00, 0x00, 0x00, 0x00,  // Code for char z
+    0x03, 0x00, 0x08, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char {
+    0x02, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char |
+    0x03, 0x00, 0x77, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,  // Code for char }
+    0x04, 0x02, 0x01, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00,  // Code for char ~
+    0x02, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00   // Code for char 
+    };
+
+#endif // SMALL_6_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/RA8875/TextDisplay.cpp	Mon Nov 30 11:13:18 2015 +0000
@@ -0,0 +1,108 @@
+/* mbed TextDisplay Display Library Base Class
+ * Copyright (c) 2007-2009 sford
+ * Released under the MIT License: http://mbed.org/license/mit
+ */
+
+#include "TextDisplay.h"
+
+//#define DEBUG "Text"
+// ...
+// INFO("Stuff to show %d", var); // new-line is automatically appended
+//
+#if (defined(DEBUG) && !defined(TARGET_LPC11U24))
+#define INFO(x, ...) std::printf("[INF %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
+#define WARN(x, ...) std::printf("[WRN %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
+#define ERR(x, ...)  std::printf("[ERR %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
+#else
+#define INFO(x, ...)
+#define WARN(x, ...)
+#define ERR(x, ...)
+#endif
+
+TextDisplay::TextDisplay(const char *name) : Stream(name)
+{
+    _row = 0;
+    _column = 0;
+    if (name == NULL) {
+        _path = NULL;
+    } else {
+        _path = new char[strlen(name) + 2];
+        sprintf(_path, "/%s", name);
+    }
+}
+
+int TextDisplay::_putc(int value)
+{
+    INFO("_putc(%d)", value);
+    if(value == '\n') {
+        _column = 0;
+        _row++;
+        if(_row >= rows()) {
+            _row = 0;
+        }
+    } else {
+        character(_column, _row, value);
+        _column++;
+        if(_column >= columns()) {
+            _column = 0;
+            _row++;
+            if(_row >= rows()) {
+                _row = 0;
+            }
+        }
+    }
+    return value;
+}
+
+// crude cls implementation, should generally be overwritten in derived class
+RetCode_t TextDisplay::cls(uint16_t layers)
+{
+    INFO("cls()");
+    locate(0, 0);
+    for(int i=0; i<columns()*rows(); i++) {
+        putc(' ');
+    }
+    return noerror;
+}
+
+RetCode_t TextDisplay::locate(textloc_t column, textloc_t row)
+{
+    INFO("locate(%d,%d)", column, row);
+    _column = column;
+    _row = row;
+    return noerror;
+}
+
+int TextDisplay::_getc()
+{
+    return -1;
+}
+
+RetCode_t TextDisplay::foreground(uint16_t color)
+{
+    //INFO("foreground(%4X)", color);
+    _foreground = color;
+    return noerror;
+}
+
+RetCode_t TextDisplay::background(uint16_t color)
+{
+    //INFO("background(%4X)", color);
+    _background = color;
+    return noerror;
+}
+
+bool TextDisplay::claim(FILE *stream)
+{
+    if ( _path == NULL) {
+        fprintf(stderr, "claim requires a name to be given in the instantiator of the TextDisplay instance!\r\n");
+        return false;
+    }
+    if (freopen(_path, "w", stream) == NULL) {
+        return false;       // Failed, should not happen
+    }
+    // make sure we use line buffering
+    setvbuf(stdout, NULL, _IOLBF, columns());
+    return true;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/RA8875/TextDisplay.h	Mon Nov 30 11:13:18 2015 +0000
@@ -0,0 +1,136 @@
+/* mbed TextDisplay Library Base Class
+ * Copyright (c) 2007-2009 sford
+ * Released under the MIT License: http://mbed.org/license/mit
+ *
+ * A common base class for Text displays
+ * To port a new display, derive from this class and implement
+ * the constructor (setup the display), character (put a character
+ * at a location), rows and columns (number of rows/cols) functions.
+ * Everything else (locate, printf, putc, cls) will come for free
+ *
+ * The model is the display will wrap at the right and bottom, so you can
+ * keep writing and will always get valid characters. The location is
+ * maintained internally to the class to make this easy
+ */
+
+#ifndef MBED_TEXTDISPLAY_H
+#define MBED_TEXTDISPLAY_H
+
+#include "mbed.h"
+
+#include "DisplayDefs.h"
+
+/// A text display class that supports character based
+/// presentation.
+///
+class TextDisplay : public Stream
+{
+public:
+
+    // functions needing implementation in derived implementation class
+    /// Create a TextDisplay interface
+    ///
+    /// @param name The name used in the path to access the display through 
+    ///     the stdio stream.
+    ///
+    TextDisplay(const char *name = NULL);
+
+    /// output a character at the given position
+    ///
+    /// @note this method may be overridden in a derived class.
+    ///
+    /// @param[in] x position in pixels
+    /// @param[in] y position in pixels
+    /// @param[in] c the character to be written to the TextDisplay
+    /// @returns number of pixels to advance the cursor which could be the cell width
+    ///     for non-proportional characters, or the actual character width for
+    ///     proportional characters.
+    ///
+    virtual int character(int x, int y, int c) = 0;
+
+    /// return number of rows on TextDisplay
+    ///
+    /// @note this method may be overridden in a derived class.
+    ///
+    /// @returns number of text rows for the display for the currently 
+    ///     active font.
+    ///
+    virtual int rows() = 0;
+
+    /// return number if columns on TextDisplay
+    ///
+    /// @note this method may be overridden in a derived class.
+    ///
+    /// @returns number of text rows for the display for the currently
+    ///     active font.
+    ///
+    virtual int columns() = 0;
+
+    // functions that come for free, but can be overwritten
+
+    /// redirect output from a stream (stoud, sterr) to  display
+    ///
+    /// @note this method may be overridden in a derived class.
+    ///
+    /// @param[in] stream that shall be redirected to the TextDisplay
+    /// @returns true if the claim succeeded.
+    ///
+    virtual bool claim (FILE *stream);
+
+    /// clear screen
+    ///
+    /// @note this method may be overridden in a derived class.
+    ///
+    /// @param[in] layers is ignored, but supports maintaining the same 
+    ///     API for the graphics layer.
+    /// @returns error code.
+    ///
+    virtual RetCode_t cls(uint16_t layers = 0) = 0;
+    
+    /// locate the cursor at a character position.
+    ///
+    /// Based on the currently active font, locate the cursor on screen.
+    ///
+    /// @note this method may be overridden in a derived class.
+    ///
+    /// @param[in] column is the horizontal offset from the left side.
+    /// @param[in] row is the vertical offset from the top.
+    /// @returns error code.
+    ///
+    virtual RetCode_t locate(textloc_t column, textloc_t row) = 0;
+    
+    /// set the foreground color
+    ///
+    /// @note this method may be overridden in a derived class.
+    ///
+    /// @param[in] color is color to use for foreground drawing.
+    /// @returns error code.
+    ///
+    virtual RetCode_t foreground(color_t color) = 0;
+
+    /// set the background color
+    ///
+    /// @note this method may be overridden in a derived class.
+    ///
+    /// @param[in] color is color to use for background drawing.
+    /// @returns error code.
+    ///
+    virtual RetCode_t background(color_t color) = 0;
+    // putc (from Stream)
+    // printf (from Stream)
+
+protected:    
+    virtual int _putc(int value);
+    virtual int _getc();
+
+    // character location
+    uint16_t _column;
+    uint16_t _row;
+
+    // colors
+    color_t _foreground;
+    color_t _background;
+    char *_path;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/RA8875/WebColors.h	Mon Nov 30 11:13:18 2015 +0000
@@ -0,0 +1,38 @@
+
+#ifndef WEBCOLORS_H
+#define WEBCOLORS_H
+
+#include "RA8875.h"
+
+const color_t WebColors[256] =
+    {
+    RGB(0x00,0x00,0x00), RGB(0x00,0x00,0x33), RGB(0x00,0x00,0x66), RGB(0x00,0x00,0x99), RGB(0x00,0x00,0xCC), RGB(0x00,0x00,0xFF), RGB(0x00,0x33,0x00), RGB(0x00,0x33,0x33), 
+    RGB(0x00,0x33,0x66), RGB(0x00,0x33,0x99), RGB(0x00,0x33,0xCC), RGB(0x00,0x33,0xFF), RGB(0x00,0x66,0x00), RGB(0x00,0x66,0x33), RGB(0x00,0x66,0x66), RGB(0x00,0x66,0x99), 
+    RGB(0x00,0x66,0xCC), RGB(0x00,0x66,0xFF), RGB(0x00,0x99,0x00), RGB(0x00,0x99,0x33), RGB(0x00,0x99,0x66), RGB(0x00,0x99,0x99), RGB(0x00,0x99,0xCC), RGB(0x00,0x99,0xFF), 
+    RGB(0x00,0xCC,0x00), RGB(0x00,0xCC,0x33), RGB(0x00,0xCC,0x66), RGB(0x00,0xCC,0x99), RGB(0x00,0xCC,0xCC), RGB(0x00,0xCC,0xFF), RGB(0x00,0xFF,0x00), RGB(0x00,0xFF,0x33), 
+    RGB(0x00,0xFF,0x66), RGB(0x00,0xFF,0x99), RGB(0x00,0xFF,0xCC), RGB(0x00,0xFF,0xFF), RGB(0x33,0x00,0x00), RGB(0x33,0x00,0x33), RGB(0x33,0x00,0x66), RGB(0x33,0x00,0x99), 
+    RGB(0x33,0x00,0xCC), RGB(0x33,0x00,0xFF), RGB(0x33,0x33,0x00), RGB(0x33,0x33,0x33), RGB(0x33,0x33,0x66), RGB(0x33,0x33,0x99), RGB(0x33,0x33,0xCC), RGB(0x33,0x33,0xFF), 
+    RGB(0x33,0x66,0x00), RGB(0x33,0x66,0x33), RGB(0x33,0x66,0x66), RGB(0x33,0x66,0x99), RGB(0x33,0x66,0xCC), RGB(0x33,0x66,0xFF), RGB(0x33,0x99,0x00), RGB(0x33,0x99,0x33), 
+    RGB(0x33,0x99,0x66), RGB(0x33,0x99,0x99), RGB(0x33,0x99,0xCC), RGB(0x33,0x99,0xFF), RGB(0x33,0xCC,0x00), RGB(0x33,0xCC,0x33), RGB(0x33,0xCC,0x66), RGB(0x33,0xCC,0x99), 
+    RGB(0x33,0xCC,0xCC), RGB(0x33,0xCC,0xFF), RGB(0x33,0xFF,0x00), RGB(0x33,0xFF,0x33), RGB(0x33,0xFF,0x66), RGB(0x33,0xFF,0x99), RGB(0x33,0xFF,0xCC), RGB(0x33,0xFF,0xFF), 
+    RGB(0x66,0x00,0x00), RGB(0x66,0x00,0x33), RGB(0x66,0x00,0x66), RGB(0x66,0x00,0x99), RGB(0x66,0x00,0xCC), RGB(0x66,0x00,0xFF), RGB(0x66,0x33,0x00), RGB(0x66,0x33,0x33), 
+    RGB(0x66,0x33,0x66), RGB(0x66,0x33,0x99), RGB(0x66,0x33,0xCC), RGB(0x66,0x33,0xFF), RGB(0x66,0x66,0x00), RGB(0x66,0x66,0x33), RGB(0x66,0x66,0x66), RGB(0x66,0x66,0x99), 
+    RGB(0x66,0x66,0xCC), RGB(0x66,0x66,0xFF), RGB(0x66,0x99,0x00), RGB(0x66,0x99,0x33), RGB(0x66,0x99,0x66), RGB(0x66,0x99,0x99), RGB(0x66,0x99,0xCC), RGB(0x66,0x99,0xFF), 
+    RGB(0x66,0xCC,0x00), RGB(0x66,0xCC,0x33), RGB(0x66,0xCC,0x66), RGB(0x66,0xCC,0x99), RGB(0x66,0xCC,0xCC), RGB(0x66,0xCC,0xFF), RGB(0x66,0xFF,0x00), RGB(0x66,0xFF,0x33), 
+    RGB(0x66,0xFF,0x66), RGB(0x66,0xFF,0x99), RGB(0x66,0xFF,0xCC), RGB(0x66,0xFF,0xFF), RGB(0x99,0x00,0x00), RGB(0x99,0x00,0x33), RGB(0x99,0x00,0x66), RGB(0x99,0x00,0x99), 
+    RGB(0x99,0x00,0xCC), RGB(0x99,0x00,0xFF), RGB(0x99,0x33,0x00), RGB(0x99,0x33,0x33), RGB(0x99,0x33,0x66), RGB(0x99,0x33,0x99), RGB(0x99,0x33,0xCC), RGB(0x99,0x33,0xFF), 
+    RGB(0x99,0x66,0x00), RGB(0x99,0x66,0x33), RGB(0x99,0x66,0x66), RGB(0x99,0x66,0x99), RGB(0x99,0x66,0xCC), RGB(0x99,0x66,0xFF), RGB(0x99,0x99,0x00), RGB(0x99,0x99,0x33), 
+    RGB(0x99,0x99,0x66), RGB(0x99,0x99,0x99), RGB(0x99,0x99,0xCC), RGB(0x99,0x99,0xFF), RGB(0x99,0xCC,0x00), RGB(0x99,0xCC,0x33), RGB(0x99,0xCC,0x66), RGB(0x99,0xCC,0x99), 
+    RGB(0x99,0xCC,0xCC), RGB(0x99,0xCC,0xFF), RGB(0x99,0xFF,0x00), RGB(0x99,0xFF,0x33), RGB(0x99,0xFF,0x66), RGB(0x99,0xFF,0x99), RGB(0x99,0xFF,0xCC), RGB(0x99,0xFF,0xFF), 
+    RGB(0xCC,0x00,0x00), RGB(0xCC,0x00,0x33), RGB(0xCC,0x00,0x66), RGB(0xCC,0x00,0x99), RGB(0xCC,0x00,0xCC), RGB(0xCC,0x00,0xFF), RGB(0xCC,0x33,0x00), RGB(0xCC,0x33,0x33), 
+    RGB(0xCC,0x33,0x66), RGB(0xCC,0x33,0x99), RGB(0xCC,0x33,0xCC), RGB(0xCC,0x33,0xFF), RGB(0xCC,0x66,0x00), RGB(0xCC,0x66,0x33), RGB(0xCC,0x66,0x66), RGB(0xCC,0x66,0x99), 
+    RGB(0xCC,0x66,0xCC), RGB(0xCC,0x66,0xFF), RGB(0xCC,0x99,0x00), RGB(0xCC,0x99,0x33), RGB(0xCC,0x99,0x66), RGB(0xCC,0x99,0x99), RGB(0xCC,0x99,0xCC), RGB(0xCC,0x99,0xFF), 
+    RGB(0xCC,0xCC,0x00), RGB(0xCC,0xCC,0x33), RGB(0xCC,0xCC,0x66), RGB(0xCC,0xCC,0x99), RGB(0xCC,0xCC,0xCC), RGB(0xCC,0xCC,0xFF), RGB(0xCC,0xFF,0x00), RGB(0xCC,0xFF,0x33), 
+    RGB(0xCC,0xFF,0x66), RGB(0xCC,0xFF,0x99), RGB(0xCC,0xFF,0xCC), RGB(0xCC,0xFF,0xFF), RGB(0xFF,0x00,0x00), RGB(0xFF,0x00,0x33), RGB(0xFF,0x00,0x66), RGB(0xFF,0x00,0x99), 
+    RGB(0xFF,0x00,0xCC), RGB(0xFF,0x00,0xFF), RGB(0xFF,0x33,0x00), RGB(0xFF,0x33,0x33), RGB(0xFF,0x33,0x66), RGB(0xFF,0x33,0x99), RGB(0xFF,0x33,0xCC), RGB(0xFF,0x33,0xFF), 
+    RGB(0xFF,0x66,0x00), RGB(0xFF,0x66,0x33), RGB(0xFF,0x66,0x66), RGB(0xFF,0x66,0x99), RGB(0xFF,0x66,0xCC), RGB(0xFF,0x66,0xFF), RGB(0xFF,0x99,0x00), RGB(0xFF,0x99,0x33), 
+    RGB(0xFF,0x99,0x66), RGB(0xFF,0x99,0x99), RGB(0xFF,0x99,0xCC), RGB(0xFF,0x99,0xFF), RGB(0xFF,0xCC,0x00), RGB(0xFF,0xCC,0x33), RGB(0xFF,0xCC,0x66), RGB(0xFF,0xCC,0x99), 
+    RGB(0xFF,0xCC,0xCC), RGB(0xFF,0xCC,0xFF), RGB(0xFF,0xFF,0x00), RGB(0xFF,0xFF,0x33), RGB(0xFF,0xFF,0x66), RGB(0xFF,0xFF,0x99), RGB(0xFF,0xFF,0xCC), RGB(0xFF,0xFF,0xFF)
+    };
+
+#endif // WEBCOLORS_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Mon Nov 30 11:13:18 2015 +0000
@@ -0,0 +1,438 @@
+#include "mbed.h"
+#include "RA8875.h"
+
+Serial Fc(p28, p27);
+
+int fuelcellStatus = -1;
+int fuelcellAmbientRawT;
+float fuelcellAmbientT;
+int fuelcellStackRawV;
+int fuelcellStackRawIHighByte;
+int fuelcellStackRawILowByte;
+int fuelcellStackRawH2Sensor;
+
+int fuelcellStackRawT;
+int fuelcellRawOutputCurrent1; //high byte
+int fuelcellRawOutputCurrent2; //low byte
+int fuelcellBatteryRawV;
+float fuelcellStackV;
+float fuelcellStackI;
+float h2SensorVoltage;
+float fuelcellStackPower;
+float fuelcellStackT;
+float fuelcellOutputCurrent;// 
+float fuelcellBatteryV;
+float PWRused = 0.0;
+
+InterruptIn S(p15);
+float speed = 0.0;
+float avgspeed = 0.0;
+float necspeed = 0.0;
+float wielomtrek = 1.75;
+bool rond = 0;
+Timer t;
+Timer teller;
+Ticker tick;
+
+int seconde = 0;
+int sec = 0;
+int min = 0;
+int lmin = 39;
+int lsec = 0;
+
+float afstandtogo = 17000.0;
+float afstand = 0.0;
+float tijd = 39.0*60.0;
+color_t Kleur1;
+color_t Kleur6;
+
+
+
+void tel(){
+            rond=1;
+        } 
+    
+    
+void counters(){
+    seconde++;
+    PWRused += (fuelcellStackPower * (1.0/3600.0));
+    if(seconde >= 39*60)
+    {
+
+    min = 39;
+    sec = 00;
+  lmin = 00;
+ lsec = 00;
+    Kleur1 = BrightRed;
+    Kleur6 = BrightRed;
+    }
+    else if(seconde >= 34*60)
+    {
+       
+        min = seconde/60;
+        sec = seconde - (min*60);
+        lsec--;
+        if(lsec < 0){
+        lsec = 59;
+        lmin--;
+        }
+        
+        Kleur1 = Yellow;
+        Kleur6 = Yellow;
+    }
+    else
+    {
+        
+        min = seconde/60;
+        sec = seconde - (min*60);
+        lsec--;
+        if(lsec < 0){
+        lsec = 59;
+        lmin--;
+        }
+              
+        Kleur1 = BrightGreen;
+        Kleur6 = BrightGreen;
+    }
+    
+    }
+    
+    void snelheidmeten(){
+        if (rond){
+        speed = (wielomtrek/t.read())*3,6;
+        afstand += wielomtrek;
+        t.reset();
+        }
+        tijd -= teller.read();
+        necspeed = ((afstandtogo-afstand)/tijd)*3.6;
+        avgspeed = (afstand/teller.read())*3.6;
+        
+        if(t.read() > 2.5)
+        speed = 0.0;
+        
+        rond = 0;
+
+        }
+    
+    void checkIncomingFcData() {
+
+    // anything in the buffer? yes check if its a valid packet. no, return
+    if (Fc.readable()) {
+
+
+
+                        fuelcellStatus = Fc.getc();
+                        fuelcellAmbientRawT = Fc.getc();
+                        fuelcellStackRawV = Fc.getc();
+                        fuelcellStackRawH2Sensor = Fc.getc();
+                        fuelcellStackRawT= Fc.getc();
+                        fuelcellStackRawIHighByte = Fc.getc();
+                        fuelcellStackRawILowByte = Fc.getc();
+                        fuelcellBatteryRawV = Fc.getc();
+
+                        //calculate actual values
+                        fuelcellAmbientT = fuelcellAmbientRawT * .5;
+                        fuelcellStackV = fuelcellStackRawV * .33333;
+                        fuelcellStackT = fuelcellStackRawT * .5;
+                        fuelcellStackI = ((fuelcellStackRawIHighByte<<8) + fuelcellStackRawILowByte) * .2;// 
+                        fuelcellBatteryV = fuelcellBatteryRawV * .10;
+                        fuelcellStackPower = fuelcellStackI * fuelcellStackV;
+                        h2SensorVoltage = fuelcellStackRawH2Sensor *.10;
+
+                    }
+                }
+
+    
+    
+    
+    
+int main()
+{
+    teller.start();
+    t.start();
+    S.rise(&tel);
+    float f = 10000000;
+    
+    
+    RA8875 lcd(p5, p6, p7, p12, NC, "tft");    // MOSI, MISO, SCK, /ChipSelect, /reset, name
+    lcd.init(800, 480, 24, true, false, false); 
+
+    lcd.frequency(f);
+    AnalogIn ain(A5);
+    tick.attach(&counters, 1.0);
+    lcd.cls();
+    wait_ms(250);
+    
+
+
+
+    lcd.background(White);
+    lcd.fillrect(     0,0, 800,480,              White);
+    lcd.fillrect(     0,79,  800,81 ,            Black);   // hor strepen over het hele beeld
+    lcd.fillrect(     0,159, 800,161,            Black);
+    lcd.fillrect(     0,239, 800,241,            Black);
+    lcd.fillrect(     0,319, 800,321,            Black);
+    lcd.fillrect(     0,399, 800,401,            Black);
+    
+    lcd.fillrect(     759,80 , 761,240,          Black);   //verticale streep boven
+    lcd.fillrect(     759,320, 761,480,          Black);   //verticale streep onder
+    
+    lcd.fillrect(     371,119, 800,121,          Black);   //hor strepen vanaf halve cirkel
+    lcd.fillrect(     396,199, 800,201,          Black);
+    lcd.fillrect(     371,359, 800,361,          Black);
+    lcd.fillrect(     315,439, 800,441,          Black);
+
+    lcd.line(         209,0  , 280,80 ,          Black);   //binnenste halve cirkel
+    lcd.line(         280,80 , 321,160,          Black);
+    lcd.line(         321,160, 331,240,          Black);
+    lcd.line(         331,240, 321,320,          Black);
+    lcd.line(         321,320, 280,400,          Black);
+    lcd.line(         280,400, 209,480,          Black);
+    
+    lcd.line(         209+70,0  , 280+70,80 ,    Black);   //buitenste halve cirkel (+70)
+    lcd.line(         280+70,80 , 321+70,160,    Black);
+    lcd.line(         321+70,160, 331+70,240,    Black);    
+    lcd.line(         331+70,240, 321+70,320,    Black);
+    lcd.line(         321+70,320, 280+70,400,    Black);
+    lcd.line(         280+70,400, 209+70,480,    Black);
+    
+    Kleur1 = BrightGreen;
+    Kleur6 = BrightGreen;
+
+    lcd.SetTextFontSize(2,2);
+    int H = lcd.fontheight()/2;
+    lcd.puts(411,40-H, "STATUS FUEL CELL");
+    lcd.puts(411,280-H, "GENERAL STATUS");
+    
+    lcd.SetTextFontSize(1,1);
+    H = lcd.fontheight()/2;
+    
+    
+    color_t Kleur2;
+    color_t Kleur3;
+    color_t Kleur4;
+    color_t Kleur5;
+    
+    color_t KleurA;
+    color_t KleurB;
+    color_t KleurC;
+    color_t KleurD;
+    color_t KleurE;
+    color_t KleurF;
+    color_t KleurG;
+    color_t KleurH;
+    
+    
+while(1){
+    checkIncomingFcData();
+    snelheidmeten();
+        
+if (avgspeed >= 26.0 && avgspeed <= 27.3)
+{
+     
+     Kleur2 = BrightGreen;
+     }
+     else if(avgspeed <= 25.0 || avgspeed >= 28.5)
+     Kleur2 = BrightRed;
+     else{
+         Kleur2 = Yellow;
+         }
+     Kleur3 = BrightBlue;
+     
+     
+     Kleur4 = BrightBlue;
+     
+     
+     Kleur5 = BrightBlue;
+     
+     if(fuelcellStackV >= 22 && fuelcellStackV <= 45)
+     {
+     KleurA = BrightGreen;
+     }
+     else if(fuelcellStackV <= 20 || fuelcellStackV >= 48){
+         KleurA = BrightRed;
+         }
+         else{
+             KleurA = Yellow;
+             } 
+         
+     
+if(fuelcellStackI <= 25)
+     {
+     KleurB = BrightGreen;
+     }
+     else if(fuelcellStackI >= 27){
+         KleurB = BrightRed;
+         }
+         else{
+             KleurB = Yellow;
+             } 
+     
+     
+
+     if(fuelcellStackPower <=1000){
+         KleurC = BrightGreen;
+         }
+         else if(fuelcellStackPower >= 1200){
+             KleurC = BrightRed;
+             }
+             else{
+                 KleurC = Yellow;
+                 }
+                 
+     
+     if(fuelcellStackT <=38){
+         KleurD = BrightGreen;
+         }
+         else if(fuelcellStackT >= 40){
+             KleurD = BrightRed;
+             }
+             else{
+                 KleurD = Yellow;
+                 }
+     
+     
+     if((ain*20*3.3) <=45){
+         KleurE = BrightGreen;
+         }
+         else if((ain*20*3.3) >= 48){
+             KleurE = BrightRed;
+             }
+             else{
+                 KleurE = Yellow;
+                 }
+     
+     
+     if(fuelcellAmbientT <=28){
+         KleurF = BrightGreen;
+         }
+         else if(fuelcellAmbientT >= 30){
+             KleurF = BrightRed;
+             }
+             else{
+                 KleurF = Yellow;
+                 }
+     
+    
+
+     
+
+
+
+    lcd.foreground(Black);
+
+    lcd.SetTextCursor(10,40-H);                     //16
+    lcd.printf("Total time       %02d:%02d",min,sec );
+    lcd.SetTextCursor(10,120-H);
+    lcd.printf("Average speed    %.1f km/h   ",avgspeed);
+    lcd.SetTextCursor(10,200-H);
+    lcd.printf("Necessary speed  %.1f km/h   ",necspeed);
+    lcd.SetTextCursor(10,280-H);
+    lcd.printf("Actual speed     %.1f km/h   ",speed);
+    lcd.SetTextCursor(10,360-H);
+    lcd.printf("Power used       %.1f Wh   ",PWRused);
+    lcd.SetTextCursor(10,440-H);
+    lcd.printf("Time left        %02d:%02d",lmin,lsec);
+    
+    lcd.SetTextCursor(411,100-H);
+    lcd.printf("Voltage fuel cell        %.2f V   ",fuelcellStackV);
+    lcd.SetTextCursor(411,140-H);
+    lcd.printf("Current fuel cell        %.2f A   ",fuelcellStackI);
+    lcd.SetTextCursor(411,180-H);
+    lcd.printf("Power fuel cell          %.2f W   ",fuelcellStackPower);
+    lcd.SetTextCursor(411,220-H);
+    lcd.printf("Temperature fuel cell    %.2f %cC   ",fuelcellStackT,176);
+    lcd.SetTextCursor(411,340-H);
+    lcd.printf("Voltage supercapacitors  %.2f V    ",ain*20*3.3);
+    lcd.SetTextCursor(411,380-H);
+    lcd.printf("Ambient temperature      %.2f %cC   ",fuelcellAmbientT,176);
+    lcd.SetTextCursor(411,420-H);
+    
+    switch(fuelcellStatus)
+{
+  case 0:
+lcd.printf("Status fuelcell:         NORMAL          ");
+     KleurG = BrightGreen;     
+     KleurH = BrightGreen;
+  break;
+ 
+  case 1:
+lcd.printf("Status fuelcell:         BATTERY LOW     ");
+     KleurG = BrightRed;     
+     KleurH = BrightRed;
+  break;
+  
+  case 2:
+lcd.printf("Status fuelcell:         FC VOLTAGE LOW  ");
+     KleurG = BrightRed;     
+     KleurH = BrightRed;
+  break;
+  
+  case 3:
+lcd.printf("Status fuelcell:         H2% HIGH        ");
+     KleurG = BrightRed;     
+     KleurH = BrightRed;
+  break;
+  
+    case 4:
+lcd.printf("Status fuelcell:         CURRENT HIGH    ");
+     KleurG = BrightRed;     
+     KleurH = BrightRed;
+  break;
+  
+    case 5:
+lcd.printf("Status fuelcell:         TEMPERATURE HIGH");
+     KleurG = BrightRed;     
+     KleurH = BrightRed;
+  break;
+  
+    case 20:
+lcd.printf("Status fuelcell:         MANUAL TURN OFF ");
+     KleurG = BrightRed;     
+     KleurH = BrightRed;
+  break;
+ 
+  default:
+lcd.printf("Status fuelcell:         NO STATUS       ");
+     KleurG = Yellow;     
+     KleurH = Yellow;
+}
+    
+    
+    
+    
+
+    
+    // vakjes in de halve cirkel
+    lcd.filltriangle( 210,0, 281,78, 278,0,      Kleur1);  //vakje 1
+    lcd.filltriangle( 349,78, 281,78, 278,0,     Kleur1);
+    
+    lcd.filltriangle( 281,82, 322,158, 349,82,   Kleur2);  //vakje 2
+    lcd.filltriangle( 390,158, 322,158, 349,82,  Kleur2);
+    
+    lcd.filltriangle( 322,162, 332,238, 390,162, Kleur3);  //vakje 3
+    lcd.filltriangle( 400,238, 332,238, 390,162, Kleur3);
+    
+    lcd.filltriangle( 332,242, 322,318, 400,242, Kleur4);  //vakje 4
+    lcd.filltriangle( 390,318, 322,318, 400,242, Kleur4);
+    
+    lcd.filltriangle( 322,322, 281,398, 390,322, Kleur5);  //vakje 5
+    lcd.filltriangle( 349,398, 281,398, 390,322, Kleur5);
+    
+    lcd.filltriangle( 281,402, 210,480, 349,402, Kleur6);  //vakje 6
+    lcd.filltriangle( 278,480, 210,480, 349,402, Kleur6);
+    
+  //vierkantjes aan de rechterkant
+    
+    lcd.fillrect(     762,82,  800,118,          KleurA); // Vierkant A
+    lcd.fillrect(     762,122, 800,158,          KleurB); // Vierkant B
+    lcd.fillrect(     762,162, 800,198,          KleurC); // Vierkant C
+    lcd.fillrect(     762,202, 800,238,          KleurD); // Vierkant D
+    lcd.fillrect(     762,322, 800,358,          KleurE); // Vierkant E
+    lcd.fillrect(     762,362, 800,398,          KleurF); // Vierkant F
+    lcd.fillrect(     762,402, 800,438,          KleurG); // Vierkant G
+    lcd.fillrect(     762,442, 800,480,          KleurH); // Vierkant H
+    
+    wait(0.2);
+    }    
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Mon Nov 30 11:13:18 2015 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/4fc01daae5a5
\ No newline at end of file