Library to control a Graphics TFT connected to 4-wire SPI - revised for the Raio RA8875 Display Controller.

Dependents:   FRDM_RA8875_mPaint RA8875_Demo RA8875_KeyPadDemo SignalGenerator ... more

Fork of SPI_TFT by Peter Drescher

See Components - RA8875 Based Display

Enhanced touch-screen support - where it previous supported both the Resistive Touch and Capacitive Touch based on the FT5206 Touch Controller, now it also has support for the GSL1680 Touch Controller.

Offline Help Manual (Windows chm)

/media/uploads/WiredHome/ra8875.zip.bin (download, rename to .zip and unzip)

Revision:
198:9b6851107426
Parent:
197:853d08e2fb53
Child:
200:ae29b60d087c
--- a/RA8875.cpp	Tue Feb 11 21:51:42 2020 +0000
+++ b/RA8875.cpp	Sat Mar 28 15:01:38 2020 +0000
@@ -297,7 +297,7 @@
     touchState = no_touch;
     numberOfTouchPoints = 0;
     gesture = 0;
-    panelTouched = 0;
+    panelTouched = false;
     touchSample = 0;
     memset(&tpMatrix, 0, sizeof(tpMatrix_t));
     pKeyMap = NULL;
@@ -305,10 +305,9 @@
     spiwritefreq = 1000000;
     spireadfreq = 1000000;
     screenbpp = 16;
-    screenwidth = 0;
-    screenheight = 0;
+    virt_screenwidth = 0;
+    virt_screenheight = 0;
     memset(&windowrect, 0, sizeof(rect_t));
-    portraitmode = false;
     font = NULL;
     extFontHeight = 0;
     extFontWidth = 0;
@@ -331,10 +330,11 @@
     frequency(RA8875_DEFAULT_SPI_FREQ);         // data rate
     Reset();
     // Set PLL based on display size from buy-display.com sample code
+    // RAIO Reference display values noted: 800w: 0x0B, 480w: 0x0A
     if (width == 800) {
-        WriteCommand(RA8875_PLLC1, 0x0C);               // PLLC1 - Phase Lock Loop registers
+        WriteCommand(RA8875_PLLC1, 0x0C);               // PLLC1 - Phase Lock Loop registers [RAIO 0B]
     } else {
-        WriteCommand(RA8875_PLLC1, 0x0B);               // PLLC1 - Phase Lock Loop registers
+        WriteCommand(RA8875_PLLC1, 0x0B);               // PLLC1 - Phase Lock Loop registers [RAIO 0A]
     }
     wait_us(1000);
     WriteCommand(RA8875_PLLC2, 0x02);
@@ -354,28 +354,28 @@
         wait_us(1000);
 
         // Horizontal Settings
-        screenwidth = width;
+        virt_screenwidth = width;
         WriteCommand(RA8875_HDWR, width/8 - 1);            //HDWR//Horizontal Display Width Setting Bit[6:0]
-        WriteCommand(RA8875_HNDFTR, 0x00);                   //HNDFCR//Horizontal Non-Display Period fine tune Bit[3:0]
-        WriteCommand(RA8875_HNDR, 0x03);                   //HNDR//Horizontal Non-Display Period Bit[4:0]
-        WriteCommand(RA8875_HSTR, 0x03);                   //HSTR//HSYNC Start Position[4:0]
-        WriteCommand(RA8875_HPWR, 0x0B);                   //HPWR//HSYNC Polarity ,The period width of HSYNC.
+        WriteCommand(RA8875_HNDFTR, 0x00);                 //HNDFCR//Horizontal Non-Display Period fine tune Bit[3:0]
+        WriteCommand(RA8875_HNDR, 0x03);                   //HNDR//Horizontal Non-Display Period Bit[4:0] [RAIO 0x01]
+        WriteCommand(RA8875_HSTR, 0x03);                   //HSTR//HSYNC Start Position[4:0] [RAIO 0x00]
+        WriteCommand(RA8875_HPWR, 0x0B);                   //HPWR//HSYNC Polarity ,The period width of HSYNC. [RAIO 0x05]
 
         // Vertical Settings
-        screenheight = height;
+        virt_screenheight = height;
         WriteCommand(RA8875_VDHR0, (height-1)&0xFF);        //VDHR0 //Vertical Display Height Bit [7:0]
         WriteCommand(RA8875_VDHR1, (height-1)>>8);          //VDHR1 //Vertical Display Height Bit [8]
-        WriteCommand(RA8875_VNDR0, 0x20);                   //VNDR0 //Vertical Non-Display Period Bit [7:0]
+        WriteCommand(RA8875_VNDR0, 0x20);                   //VNDR0 //Vertical Non-Display Period Bit [7:0] [RAIO 0x02]
         WriteCommand(RA8875_VNDR1, 0x00);                   //VNDR1 //Vertical Non-Display Period Bit [8]
-        WriteCommand(RA8875_VSTR0, 0x16);                   //VSTR0 //VSYNC Start Position[7:0]
+        WriteCommand(RA8875_VSTR0, 0x16);                   //VSTR0 //VSYNC Start Position[7:0] [RAIO 0x07]
         WriteCommand(RA8875_VSTR1, 0x00);                   //VSTR1 //VSYNC Start Position[8]
-        WriteCommand(RA8875_VPWR, 0x01);                   //VPWR  //VSYNC Polarity ,VSYNC Pulse Width[6:0]
+        WriteCommand(RA8875_VPWR, 0x01);                   //VPWR  //VSYNC Polarity ,VSYNC Pulse Width[6:0] [RAIO 0x09]
     } else {
         WriteCommand(RA8875_PCSR, 0x82);               // PDAT on PCLK falling edge, PCLK = 4 x System Clock
         wait_us(1000);
 
         // Horizontal Settings
-        screenwidth = width;
+        virt_screenwidth = width;
         WriteCommand(RA8875_HDWR, width/8 - 1);            //HDWR//Horizontal Display Width Setting Bit[6:0]
         WriteCommand(RA8875_HNDFTR, 0x02);                   //HNDFCR//Horizontal Non-Display Period fine tune Bit[3:0]
         WriteCommand(RA8875_HNDR, 0x03);                   //HNDR//Horizontal Non-Display Period Bit[4:0]
@@ -383,7 +383,7 @@
         WriteCommand(RA8875_HPWR, 0x03);                   //HPWR//HSYNC Polarity ,The period width of HSYNC.
 
         // Vertical Settings
-        screenheight = height;
+        virt_screenheight = height;
         WriteCommand(RA8875_VDHR0, (height-1)&0xFF);        //VDHR0 //Vertical Display Height Bit [7:0]
         WriteCommand(RA8875_VDHR1, (height-1)>>8);          //VDHR1 //Vertical Display Height Bit [8]
         WriteCommand(RA8875_VNDR0, 0x0F);                   //VNDR0 //Vertical Non-Display Period Bit [7:0]
@@ -393,8 +393,6 @@
         WriteCommand(RA8875_VPWR, 0x01);                   //VPWR  //VSYNC Polarity ,VSYNC Pulse Width[6:0]
     }
 
-    portraitmode = false;
-
     if (width >= 800 && height >= 480 && color_bpp > 8) {
         WriteCommand(RA8875_DPCR, 0x00);               // DPCR - 1-layer mode when the resolution is too high
     } else {
@@ -402,7 +400,7 @@
     }
 
     // Set display image to Blue on Black as default
-    window(0,0, width, height);             // Initialize to full screen
+    SetWindow(0,0, width-1, height-1);             // Initialize to full screen
     SetTextCursorControl();
     foreground(Blue);
     background(Black);
@@ -431,7 +429,7 @@
 {
     RetCode_t ret;
 
-    #if 0
+    #if 1
     if (res != (PinName)NC) {
         res = 0;                            // Active low - assert reset
         wait_us(2000);                         // must be > 1024 clock periods. (@25 MHz, this is 40.96 usec)
@@ -462,20 +460,19 @@
 }
 
 
-RetCode_t RA8875::SelectDrawingLayer(uint16_t layer, uint16_t * prevLayer)
+uint16_t RA8875::SelectDrawingLayer(uint16_t layer)
 {
+    uint16_t prevLayer;
     unsigned char mwcr1 = ReadCommand(0x41); // retain all but the currently selected layer
-
-    if (prevLayer)
-        *prevLayer = mwcr1 & 1;
-
+    prevLayer = (mwcr1 & 1);
     mwcr1 &= ~0x01; // remove the current layer
-    if (screenwidth >= 800 && screenheight >= 480 && screenbpp > 8) {
+    if (virt_screenwidth >= 800 && virt_screenheight >= 480 && screenbpp > 8) {
         layer = 0;
     } else if (layer > 1) {
         layer = 0;
     }
-    return WriteCommand(RA8875_MWCR1, mwcr1 | layer);
+    WriteCommand(RA8875_MWCR1, mwcr1 | layer);
+    return prevLayer;
 }
 
 
@@ -485,16 +482,14 @@
 }
 
 
-RetCode_t RA8875::SetLayerMode(LayerMode_T mode)
+RA8875::LayerMode_T RA8875::SetLayerMode(LayerMode_T mode)
 {
-    unsigned char ltpr0 = ReadCommand(0x52) & ~0x7; // retain all but the display layer mode
-
+    unsigned char ltpr0 = ReadCommand(0x52); // retain all but the display layer mode
+    LayerMode_T oldLayer = (LayerMode_T)(ltpr0 & 0x07);
     if (mode <= (LayerMode_T)6) {
-        WriteCommand(RA8875_LTPR0, ltpr0 | (mode & 0x7));
-        return noerror;
-    } else {
-        return bad_parameter;
+        WriteCommand(RA8875_LTPR0, (ltpr0 & ~0x07) | (mode & 0x07));
     }
+    return oldLayer;
 }
 
 
@@ -509,9 +504,11 @@
 }
 
 
-RetCode_t RA8875::SetBackgroundTransparencyColor(color_t color)
+color_t RA8875::SetBackgroundTransparencyColor(color_t color)
 {
-    return _writeColorTrio(0x67, color);
+    color_t oldColor = _readColorTrio(0x67);
+    _writeColorTrio(0x67, color);
+    return oldColor;
 }
 
 
@@ -690,36 +687,41 @@
 
 rect_t RA8875::AlignRectInRect(rect_t toAlign, rect_t inRect, valign_t v, halign_t h) {
     rect_t newRect; dim_t width; dim_t height;
-    width = toAlign.p2.x - toAlign.p1.x;
-    height = toAlign.p2.y - toAlign.p1.y;
+    width = toAlign.p2.x - toAlign.p1.x + 1;
+    height = toAlign.p2.y - toAlign.p1.y + 1;
+    INFO("Align(%d,%d)-(%d,%d) in (%d,%d)-(%d,%d) v:%d, h:%d",
+        toAlign.p1.x,toAlign.p1.y,toAlign.p2.x,toAlign.p2.y,
+        inRect.p1.x,inRect.p1.y,inRect.p2.x,inRect.p2.y,
+        v,h
+        );
     switch (h) {
         case left:
         default:
             newRect.p1.x = inRect.p1.x;
-            newRect.p2.x = newRect.p1.x + width;
+            newRect.p2.x = newRect.p1.x + width - 1;
             break;
         case center:
             newRect.p1.x = (inRect.p1.x + inRect.p2.x + 1) / 2 - width / 2;
-            newRect.p2.x = newRect.p1.x + width;
+            newRect.p2.x = newRect.p1.x + width - 1;
             break;
         case right:
-            newRect.p1.x = inRect.p2.x - width;
-            newRect.p2.x = newRect.p1.x + width;
+            newRect.p1.x = inRect.p2.x - width - 1;
+            newRect.p2.x = newRect.p1.x + width - 1;
             break;
     }
     switch (v) {
         case top:
         default:
             newRect.p1.y = inRect.p1.y;
-            newRect.p2.y = newRect.p1.y + height;
+            newRect.p2.y = newRect.p1.y + height - 1;
             break;
         case middle:
             newRect.p1.y = (inRect.p1.y + inRect.p2.y + 1) / 2 - height / 2;
-            newRect.p2.y = newRect.p1.y + height;
+            newRect.p2.y = newRect.p1.y + height - 1;
             break;
         case bottom:
-            newRect.p1.y = inRect.p2.y - height;
-            newRect.p2.y = newRect.p1.y + height;
+            newRect.p1.y = inRect.p2.y - height - 1;
+            newRect.p2.y = newRect.p1.y + height - 1;
             break;
     }
     return newRect;
@@ -1001,7 +1003,7 @@
 dim_t RA8875::fontwidth(void)
 {
     if (font == NULL)
-        return (((ReadCommand(0x22) >> 2) & 0x3) + 1) * 8;
+        return (((ReadCommand(RA8875_FNCR1) >> 2) & 0x3) + 1) * 8;
     else
         return extFontWidth;
 }
@@ -1010,13 +1012,13 @@
 dim_t RA8875::fontheight(void)
 {
     if (font == NULL)
-        return (((ReadCommand(0x22) >> 0) & 0x3) + 1) * 16;
+        return (((ReadCommand(RA8875_FNCR1) >> 0) & 0x3) + 1) * 16;
     else
         return extFontHeight;
 }
 
 
-RetCode_t RA8875::locate(textloc_t column, textloc_t row)
+point_t RA8875::locate(textloc_t column, textloc_t row)
 {
     return SetTextCursor(column * fontwidth(), row * fontheight());
 }
@@ -1024,31 +1026,25 @@
 
 int RA8875::columns(void)
 {
-    return screenwidth / fontwidth();
+    return virt_screenwidth / fontwidth();
 }
 
 
 int RA8875::rows(void)
 {
-    return screenheight / fontheight();
+    return virt_screenheight / fontheight();
 }
 
 
 dim_t RA8875::width(void)
 {
-    if (portraitmode)
-        return screenheight;
-    else
-        return screenwidth;
+    return virt_screenwidth;
 }
 
 
 dim_t RA8875::height(void)
 {
-    if (portraitmode)
-        return screenwidth;
-    else
-        return screenheight;
+    return virt_screenheight;
 }
 
 
@@ -1063,53 +1059,76 @@
     return prevWrap;
 }
 
-RetCode_t RA8875::SetTextCursor(point_t p)
+point_t RA8875::SetTextCursor(point_t p)
 {
     return SetTextCursor(p.x, p.y);
 }
 
-RetCode_t RA8875::SetTextCursor(loc_t x, loc_t y)
+point_t RA8875::SetTextCursor(loc_t x, loc_t y)
 {
-    INFO("SetTextCursor(%d, %d)", x, y);
+    point_t oldCursor = GetTextCursor();
     cursor_x = x;     // set these values for non-internal fonts
     cursor_y = y;
-    WriteCommandW(RA8875_FCURXL, x);
-    WriteCommandW(RA8875_FCURYL, y);
-    return noerror;
+    switch (screen_orientation) {
+    default:
+    case rotate_0:
+    case rotate_180:
+        WriteCommandW(RA8875_FCURXL, x);
+        WriteCommandW(RA8875_FCURYL, y);
+        break;
+    case rotate_90:
+    case rotate_270:
+        WriteCommandW(RA8875_FCURXL, y);
+        WriteCommandW(RA8875_FCURYL, x);
+        break;
+    }
+    return oldCursor;
 }
 
 point_t RA8875::GetTextCursor(void)
 {
-    point_t p;
-
-    p.x = GetTextCursor_X();
-    p.y = GetTextCursor_Y();
+    point_t p, tempPt;
+
+    if (font == NULL) {
+        p.x = ReadCommand(RA8875_FCURXL) | (ReadCommand(RA8875_FCURXH) << 8);
+        p.y = ReadCommand(RA8875_FCURYL) | (ReadCommand(RA8875_FCURYH) << 8);
+        switch (screen_orientation) {
+        case rotate_0:
+        case rotate_180:
+            // Nothing
+            break;
+        case rotate_90:
+        case rotate_270:
+            tempPt.x = p.y;
+            tempPt.y = p.x;
+            p = tempPt;
+            break;
+        default:
+            p.x = 0;
+            p.y = 0;
+            break;
+        }
+    } else {
+        p.x = cursor_x;
+        p.y = cursor_y;
+    }
+    //INFO("GetCursor hw: (%d,%d)", p.x, p.y);
     return p;
 }
 
 loc_t RA8875::GetTextCursor_Y(void)
 {
-    loc_t y;
-
-    if (font == NULL)
-        y = ReadCommand(0x2C) | (ReadCommand(0x2D) << 8);
-    else
-        y = cursor_y;
-    INFO("GetTextCursor_Y = %d", y);
-    return y;
+    point_t p = GetTextCursor();
+    INFO("GetTextCursor_Y = %d", p.y);
+    return p.y;
 }
 
 
 loc_t RA8875::GetTextCursor_X(void)
 {
-    loc_t x;
-
-    if (font == NULL)
-        x = ReadCommand(0x2A) | (ReadCommand(0x2B) << 8);
-    else
-        x = cursor_x;
-    INFO("GetTextCursor_X = %d", x);
-    return x;
+    point_t p = GetTextCursor();
+    INFO("GetTextCursor_X = %d", p.x);
+    return p.x;
 }
 
 
@@ -1161,72 +1180,87 @@
     }
 }
 
-RA8875::orientation_t RA8875::GetOrientation()
+orientation_t RA8875::GetGraphicsOrientation()
 {
-    #if 1
     return screen_orientation;
-    #else
-    uint8_t dpcrVal = ReadCommand(RA8875_DPCR);
-
-    dpcrVal &= 0x0C;       // keep the scan direction bits
-    switch (dpcrVal) {
-        default:
-        case 0x00:
-            return rotate_0;
-        case 0x08:
-            return rotate_90;
-        case 0x0C:
-            return rotate_180;
-        case 0x04:
-            return rotate_270;
-    }
-    #endif
 }
 
-RetCode_t RA8875::SetOrientation(RA8875::orientation_t angle)
+orientation_t RA8875::SetGraphicsOrientation(orientation_t angle)
 {
-    uint8_t fncr1Val = ReadCommand(RA8875_FNCR1);
     uint8_t dpcrVal = ReadCommand(RA8875_DPCR);
     uint8_t mwcr0 = ReadCommand(RA8875_MWCR0);
-    
-    fncr1Val &= ~0x10;      // remove the old direction bit
+    uint8_t mrcd = ReadCommand(RA8875_MRCD);
+    dim_t tempWidth, tempHeight;
+    orientation_t oldAngle = screen_orientation;
+
     dpcrVal &= ~0x0C;       // remove the old scan direction bits
     mwcr0 &= 0xE3;          // remove the old direction bits
+    mrcd &= 0xFC;           // remove the old direction bits
     switch (angle) {
-        case RA8875::normal:
-            //fncr1Val |= 0x10;
+        case normal:
             //dpcrVal |= 0x00;
-            portraitmode = false;
+            tempWidth = max(virt_screenwidth, virt_screenheight);
+            tempHeight = min(virt_screenwidth, virt_screenheight);
             break;
-        case RA8875::rotate_90:
-            fncr1Val |= 0x10;
+        case rotate_90:
             dpcrVal |= 0x08;
-            mwcr0 |= 0x00;
-            portraitmode = true;
+            mwcr0 |= 0x08;
+            mrcd |= 0x02;
+            tempWidth = min(virt_screenwidth, virt_screenheight);
+            tempHeight = max(virt_screenwidth, virt_screenheight);
             break;
-        case RA8875::rotate_180:
-            //fncr1Val |= 0x00;
+        case rotate_180:
             dpcrVal |= 0x0C;
             //mwcr0 |= 0x00;
-            portraitmode = false;
+            //mrcd |= 0x00;
+            tempWidth = max(virt_screenwidth, virt_screenheight);
+            tempHeight = min(virt_screenwidth, virt_screenheight);
             break;
-        case RA8875::rotate_270:
-            fncr1Val |= 0x10;
+        case rotate_270:
             dpcrVal |= 0x04;
-            mwcr0 |= 0x00;
-            portraitmode = true;
+            mwcr0 |= 0x08;
+            mrcd |= 0x02;
+            tempWidth = min(virt_screenwidth, virt_screenheight);
+            tempHeight = max(virt_screenwidth, virt_screenheight);
             break;
         default:
-            return bad_parameter;
+            return invalid;
     }
     screen_orientation = angle;
-    INFO("Orientation: %d, %s", angle * 90, portraitmode ? "portrait" : "landscape");
+    virt_screenwidth = tempWidth;
+    virt_screenheight = tempHeight;
+    WriteCommand(RA8875_MRCD, mrcd);
     WriteCommand(RA8875_MWCR0, mwcr0);
+    WriteCommand(RA8875_DPCR, dpcrVal);
+    return oldAngle;
+}
+
+orientation_t RA8875::SetTextFontOrientation(orientation_t angle)
+{
+    uint8_t fncr1Val = ReadCommand(RA8875_FNCR1);
+    orientation_t oldAngle = text_orientation;
+
+    fncr1Val &= ~0x10;      // remove the old direction bit
+    switch (angle) {
+    case normal:
+        //fncr1Val |= 0x10;
+        break;
+    case rotate_90:
+        fncr1Val |= 0x10;
+        break;
+    case rotate_180:
+        //fncr1Val |= 0x00;
+        break;
+    case rotate_270:
+        fncr1Val |= 0x10;
+        break;
+    default:
+        return invalid;
+    }
     WriteCommand(RA8875_FNCR1, fncr1Val);
-    return WriteCommand(RA8875_DPCR, dpcrVal);
+    return oldAngle;
 }
 
-
 RetCode_t RA8875::SetTextFontControl(fill_t fillit,
                                      RA8875::HorizontalScale hScale,
                                      RA8875::VerticalScale vScale,
@@ -1234,7 +1268,7 @@
 {
     if (hScale >= 1 && hScale <= 4 &&
             vScale >= 1 && vScale <= 4) {
-        uint8_t fncr1Val = ReadCommand(0x22);
+        uint8_t fncr1Val = ReadCommand(RA8875_FNCR1);
 
         fncr1Val &= 0x10;      // remove all except the font rotation bit
         if (alignment == align_full)
@@ -1252,7 +1286,7 @@
 fill_t RA8875::SetTextFontFill(fill_t fillit)
 {
     fill_t prevFill = FILL;
-    uint8_t fncr1Val = ReadCommand(0x22);
+    uint8_t fncr1Val = ReadCommand(RA8875_FNCR1);
 
     if (fncr1Val & 0x40)
         prevFill = NOFILL;
@@ -1265,14 +1299,14 @@
 
 RetCode_t RA8875::SetTextFontSize(RA8875::HorizontalScale hScale, RA8875::VerticalScale vScale)
 {
-    unsigned char reg = ReadCommand(0x22);
+    unsigned char reg = ReadCommand(RA8875_FNCR1);
 
     if (vScale == -1)
         vScale = hScale;
     if (hScale >= 1 && hScale <= 4 && vScale >= 1 && vScale <= 4) {
-        fontScaleX = hScale;    // save for use with a Soft Font
+        fontScaleX = hScale;            // save for use with a Soft Font
         fontScaleY = vScale;
-        reg &= 0xF0;    // keep the high nibble as is.
+        reg &= 0xF0;                    // keep the high nibble as is.
         reg |= ((hScale - 1) << 2);
         reg |= ((vScale - 1) << 0);
         WriteCommand(RA8875_FNCR1, reg);
@@ -1284,7 +1318,7 @@
 
 RetCode_t RA8875::GetTextFontSize(RA8875::HorizontalScale * hScale, RA8875::VerticalScale * vScale)
 {
-    unsigned char reg = ReadCommand(0x22);
+    unsigned char reg = ReadCommand(RA8875_FNCR1);
 
     if (hScale)
         *hScale = 1 + ((reg >> 2) & 0x03);
@@ -1297,9 +1331,9 @@
 {
     if (font == NULL) {
         if (charOnly)
-            return fontwidth();     // *fontScaleX;  // fontScale is picked up from fontwidth()
+            return fontwidth();
         else
-            return fontwidth() * strlen(text);// *fontScaleX;
+            return fontwidth() * strlen(text);
     } else {
         dim_t width = 0;
 
@@ -1341,13 +1375,7 @@
             cursor_y += extFontHeight;
         } else {
             dim_t charWidth, charHeight;
-            const uint8_t * charRecord;
-
-            charRecord = getCharMetrics(c, &charWidth, &charHeight);
-            //int advance = charwidth(c);
-            INFO("(%d,%d) - (%d,%d):(%d,%d), charWidth: %d '%c", cursor_x, cursor_y,
-                windowrect.p1.x, windowrect.p1.y, windowrect.p2.x, windowrect.p2.y,
-                charWidth, c);
+            const uint8_t * charRecord = getCharMetrics(c, &charWidth, &charHeight);
             if (charRecord) {
                 //cursor_x += advance;
                 if (cursor_x + charWidth >= windowrect.p2.x) {
@@ -1369,22 +1397,19 @@
 int RA8875::_internal_putc(int c)
 {
     if (c) {
-        unsigned char mwcr0;
-
-        mwcr0 = ReadCommand(RA8875_MWCR0);
+        unsigned char mwcr0 = ReadCommand(RA8875_MWCR0);
         if ((mwcr0 & 0x80) == 0x00)
             WriteCommand(RA8875_MWCR0, 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(RA8875_FCURXL, 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(RA8875_FCURYL, y);
+        if (c == '\r' || c == '\n') {
+            point_t cur = GetTextCursor();
+            if (c == '\r') {
+                cur.x = windowrect.p1.x;
+            } else if (c == '\n') {
+                cur.y += fontheight();
+                if (cur.y >= windowrect.p2.y)               // @TODO after bottom of active window, then scroll window?
+                    cur.y = windowrect.p1.y;
+            }
+            SetTextCursor(cur);
         } else {
             WriteCommand(RA8875_MRWC);                 // RA8875 Internal Fonts
             _select(true);
@@ -1403,9 +1428,9 @@
 
     mwcr0 = ReadCommand(RA8875_MWCR0) & ~0x80;
     mwcr0 |= 0x00;
-    INFO("mwcr0 %02X", mwcr0);
-    WriteCommand(RA8875_MWCR0, mwcr0);    // Graphics write mode
-    WriteCommand(RA8875_MRWC);         // Prepare for streaming data
+    //INFO("_StartGraphicsStream mwcr0: %02X", mwcr0);
+    WriteCommand(RA8875_MWCR0, mwcr0);      // Graphics write mode
+    WriteCommand(RA8875_MRWC);              // Prepare for streaming data
     return noerror;
 }
 
@@ -1438,14 +1463,12 @@
 
 void RA8875::puts(const char * string)
 {
+    INFO("puts len(%d), (%s)", strlen(string), string);
     if (font == NULL) {
-        unsigned char mwcr0;
-
-        mwcr0 = ReadCommand(RA8875_MWCR0);
+        unsigned char mwcr0 = ReadCommand(RA8875_MWCR0);
         if ((mwcr0 & 0x80) == 0x00)
             WriteCommand(RA8875_MWCR0, 0x80 | mwcr0);    // Put in Text mode if not already
     }
-    point_t cursor = GetTextCursor();
     while (string && *string) {           // @TODO calling individual _putc is slower... optimizations?
         if (wordwrap) {
             const char * p = string;
@@ -1453,9 +1476,10 @@
             dim_t txtPos;
             bool newLineNeeded = false;
 
-            cursor = GetTextCursor();
+            point_t cursor = GetTextCursor();
+            //INFO("cursor (%d,%d)", cursor.x, cursor.y);
             txtPos = cursor.x;
-            INFO("(%d,%d) string: '%s'\r\n", cursor.x, cursor.y, string);
+            INFO("(%d,%d) string: '%s'", cursor.x, cursor.y, string);
             // find what fits in the window
             do {
                 if (*p == ' ')
@@ -1468,23 +1492,39 @@
                     break;
                 }
                 dim_t cWidth = GetTextWidth(p, true);
+                INFO("txtPos: %d, cWidth: %d, p2.x: %d", txtPos, cWidth, windowrect.p2.x);
                 if (txtPos + cWidth < windowrect.p2.x) {
                     txtPos += cWidth;
                 } else {
                     newLineNeeded = true;
                     break;
                 }
-                INFO("+ %c width %d, ttl Width %d\r\n", *p, cWidth, txtPos);
+                INFO("+ %c width %d, ttl Width %d < %d", *p, cWidth, txtPos, windowrect.p2.x);
                 p++;
             } while (*p);
-            INFO(" do { } while();\r\n");
+            INFO("p: len(%d), (%s)", strlen(p), p);
             if (*p != ' ' && pSpace) {
                 p = pSpace;
+                INFO("p: len(%d), (%s)", strlen(p), p);
             }
-            INFO("txtPos: %d < windowrect.p2.x: %d\r\n", txtPos, windowrect.p2.x);
+            char dbgBuf[256];
+            strncpy(dbgBuf, string, (p - string));
+            dbgBuf[p - string] = '\0';
+            INFO("chunk: %d < w.p2.x: %d - '%s'", txtPos, windowrect.p2.x, dbgBuf);
             if (txtPos < windowrect.p2.x) {
                 while (*string && string <= p) {
-                    _putc(*string++);
+                    INFO("*string %02X", *string);
+                    if (*string == '\r') {
+                        cursor = GetTextCursor();
+                        SetTextCursor(windowrect.p1.x, cursor.y);
+                    } else if (*string == '\n') {
+                        cursor = GetTextCursor();
+                        SetTextCursor(cursor.x, cursor.y + fontheight());
+                    } else {
+                        INFO("cursor (%d,%d) - %c", cursor.x, cursor.y, *string);
+                        _putc(*string);
+                    }
+                    string++;
                 }
             }
             while (*string == ' ')
@@ -1501,13 +1541,27 @@
             _putc(*string++);
         }
     }
+    //point_t cursor = GetTextCursor();
+    //INFO("cursor (%d,%d)", cursor.x, cursor.y);
 }
 
 
 RetCode_t RA8875::SetGraphicsCursor(loc_t x, loc_t y)
 {
-    WriteCommandW(RA8875_CURH0, x);
-    WriteCommandW(RA8875_CURV0, y);
+    switch (screen_orientation) {
+    case rotate_0:
+    case rotate_180:
+        WriteCommandW(RA8875_CURH0, x);
+        WriteCommandW(RA8875_CURV0, y);
+        break;
+    case rotate_90:
+    case rotate_270:
+        WriteCommandW(RA8875_CURH0, y);
+        WriteCommandW(RA8875_CURV0, x);
+        break;
+    case invalid:
+        return bad_parameter;
+    }
     return noerror;
 }
 
@@ -1520,50 +1574,108 @@
 {
     point_t p;
 
-    p.x = ReadCommandW(0x46);
-    p.y = ReadCommandW(0x48);
+    switch (screen_orientation) {
+    case rotate_0:
+    case rotate_180:
+        p.x = ReadCommandW(RA8875_CURH0);
+        p.y = ReadCommandW(RA8875_CURV0);
+        break;
+    case rotate_90:
+    case rotate_270:
+        p.y = ReadCommandW(RA8875_CURH0);
+        p.x = ReadCommandW(RA8875_CURV0);
+        break;
+    case invalid:
+        p.x = p.y = 0;
+        break;
+    }
     return p;
 }
 
 RetCode_t RA8875::SetGraphicsCursorRead(loc_t x, loc_t y)
 {
-    WriteCommandW(RA8875_RCURH0, x);
-    WriteCommandW(RA8875_RCURV0, y);
+    switch (screen_orientation) {
+    case rotate_0:
+    case rotate_180:
+        WriteCommandW(RA8875_RCURH0, x);
+        WriteCommandW(RA8875_RCURV0, y);
+        break;
+    case rotate_90:
+    case rotate_270:
+        WriteCommandW(RA8875_RCURH0, y);
+        WriteCommandW(RA8875_RCURV0, x);
+        break;
+    case invalid:
+        return bad_parameter;
+    }
     return noerror;
 }
 
-RetCode_t RA8875::window(rect_t r)
+
+rect_t RA8875::GetWindow() {
+    return windowrect;
+}
+
+rect_t RA8875::SetWindow(rect_t r)
 {
-    return window(r.p1.x, r.p1.y, r.p2.x + 1 - r.p1.x, r.p2.y + 1 - r.p1.y);
+    return SetWindow(r.p1.x, r.p1.y, r.p2.x, r.p2.y);
 }
 
-RetCode_t RA8875::window(loc_t x, loc_t y, dim_t width, dim_t height)
+rect_t RA8875::SetWindow(loc_t x1, loc_t y1, loc_t x2, loc_t y2)
 {
-    INFO("window(%d,%d,%d,%d)", x, y, width, height);
-    if (width == (dim_t)-1)
-        width = screenwidth - x;
-    if (height == (dim_t)-1)
-        height = screenheight - y;
-    windowrect.p1.x = x;
-    windowrect.p1.y = y;
-    windowrect.p2.x = x + width - 1;
-    windowrect.p2.y = y + height - 1;
-    GraphicsDisplay::window(x,y, width,height);
-    WriteCommandW(RA8875_HSAW0, x);
-    WriteCommandW(RA8875_VSAW0, y);
-    WriteCommandW(RA8875_HEAW0, (x+width-1));
-    WriteCommandW(RA8875_VEAW0, (y+height-1));
-    //SetTextCursor(x,y);
-    //SetGraphicsCursor(x,y);
-    return noerror;
+    const rect_t nullRect = { 0,0,0,0 };    // in case it is invalid
+    rect_t oldWin = windowrect;
+    dim_t tempWidth, tempHeight;
+    //INFO("SetWindow(%d,%d)-(%d,%d)", x1,y1, x2,y2);
+    // Correct the initial values (0,-1) - (0,-1)
+    if (x2 == (loc_t)-1) x2 = virt_screenwidth - 1;
+    if (y2 == (loc_t)-1) y2 = virt_screenheight - 1;
+    // Sanity check the parameters.
+    if (x1 < 0 || y1 < 0 || x2 < 0 || y2 < 0
+        || x1 >= virt_screenwidth || y1 >= virt_screenheight 
+        || x2 >= virt_screenwidth || y2 >= virt_screenheight) {
+        return nullRect;
+    }
+    windowrect.p1.x = x1;
+    windowrect.p1.y = y1;
+    windowrect.p2.x = x2;
+    windowrect.p2.y = y2;
+    switch (screen_orientation) {
+    case rotate_0:
+    case rotate_180:
+        tempWidth = max(virt_screenwidth, virt_screenheight);
+        tempHeight = min(virt_screenwidth, virt_screenheight);
+        virt_screenwidth = tempWidth;
+        virt_screenheight = tempHeight;
+        //GraphicsDisplay::SetWindow(x1, y1, x2, y2);
+        WriteCommandW(RA8875_HSAW0, x1);
+        WriteCommandW(RA8875_VSAW0, y1);
+        WriteCommandW(RA8875_HEAW0, x2);
+        WriteCommandW(RA8875_VEAW0, y2);
+        break;
+    case rotate_90:
+    case rotate_270:
+        tempWidth = min(virt_screenwidth, virt_screenheight);
+        tempHeight = max(virt_screenwidth, virt_screenheight);
+        virt_screenwidth = tempWidth;
+        virt_screenheight = tempHeight;
+        //GraphicsDisplay::SetWindow(x1, y1, x2, y2);
+        WriteCommandW(RA8875_HSAW0, y1);
+        WriteCommandW(RA8875_VSAW0, x1);
+        WriteCommandW(RA8875_HEAW0, y2);
+        WriteCommandW(RA8875_VEAW0, x2);
+        break;
+    case invalid:
+        break;
+    }
+    return oldWin;
 }
 
-
 RetCode_t RA8875::cls(uint16_t layers)
 {
-    RetCode_t ret;
-
-    INFO("cls()");
+    RetCode_t ret = noerror;
+
+    INFO("cls(%d)", layers);
     PERFORMANCE_RESET;
     if (layers == 0) {
         ret = clsw(FULLWINDOW);
@@ -1581,7 +1693,7 @@
         }
         SelectDrawingLayer(prevLayer);
     }
-    ret = SetTextCursor(0,0);
+    SetTextCursor(0,0);
     //ret = locate(0,0);
     REGISTERPERFORMANCE(PRF_CLS);
     return ret;
@@ -1593,7 +1705,8 @@
     INFO("clsw(%d)", region);
     PERFORMANCE_RESET;
     WriteCommand(RA8875_MCLR, (region == ACTIVEWINDOW) ? 0xC0 : 0x80);
-    if (!_WaitWhileReg(0x8E, 0x80)) {
+    if (!_WaitWhileReg(RA8875_MCLR, 0x80)) {
+        WriteCommand(RA8875_MCLR, 0x00);    // Abort clearing on request
         REGISTERPERFORMANCE(PRF_CLS);
         return external_abort;
     }
@@ -1666,8 +1779,7 @@
 {
     PERFORMANCE_RESET;
     const uint8_t * rowStream = boolStream;
-    rect_t restore = windowrect;
-    window(x, y, w * fontScaleX, h * fontScaleY);       // Scale from font scale factors
+    rect_t restore = SetWindow(x, y, x + w * fontScaleX - 1, y + h * fontScaleY - 1);
     SetGraphicsCursor(x, y);
     _StartGraphicsStream();
     _select(true);
@@ -1702,7 +1814,7 @@
     }
     _select(false);
     _EndGraphicsStream();
-    window(restore);
+    SetWindow(restore);
     REGISTERPERFORMANCE(PRF_BOOLSTREAM);
     return(noerror);
 }
@@ -1788,12 +1900,39 @@
 {
     PERFORMANCE_RESET;
     if (x1 == x2 && y1 == y2) {
-        pixel(x1, y1);
+        switch (screen_orientation) {
+        case invalid:
+            return bad_parameter;
+            //break;
+        case rotate_0:
+        case rotate_180:
+            pixel(x1, y1);
+            break;
+        case rotate_90:
+        case rotate_270:
+            pixel(y1, x1);
+            break;
+        }
     } else {
-        WriteCommandW(RA8875_DLHSR0, x1);
-        WriteCommandW(RA8875_DLVSR0, y1);
-        WriteCommandW(RA8875_DLHER0, x2);
-        WriteCommandW(RA8875_DLVER0, y2);
+        switch (screen_orientation) {
+        case invalid:
+            return bad_parameter;
+            //break;
+        case rotate_0:
+        case rotate_180:
+            WriteCommandW(RA8875_DLHSR0, x1);
+            WriteCommandW(RA8875_DLVSR0, y1);
+            WriteCommandW(RA8875_DLHER0, x2);
+            WriteCommandW(RA8875_DLVER0, y2);
+            break;
+        case rotate_90:
+        case rotate_270:
+            WriteCommandW(RA8875_DLHSR0, y1);
+            WriteCommandW(RA8875_DLVSR0, x1);
+            WriteCommandW(RA8875_DLHER0, y2);
+            WriteCommandW(RA8875_DLVER0, x2);
+            break;
+        }
         unsigned char drawCmd = 0x00;       // Line
         WriteCommand(RA8875_DCR, drawCmd);
         WriteCommand(RA8875_DCR, 0x80 + drawCmd); // Start drawing.
@@ -1809,7 +1948,7 @@
 
 RetCode_t RA8875::ThickLine(point_t p1, point_t p2, dim_t thickness, color_t color)
 {
-    INFO("ThickLine()");
+    //INFO("ThickLine()");
     if (thickness == 1) {
         line(p1,p2, color);
     } else {
@@ -1831,7 +1970,6 @@
             // some diagonal, drawn rather slowly with filled circles
             // @todo draw the end-points with circles, then draw the diagonal
             //      with 2 triangles.
-            #if 1  // New Faster method
             //Round-caps
             if (roundCap) {
                 fillcircle(p1, thickness / 2, color);
@@ -1867,23 +2005,6 @@
             pTri[3].y = p2.y - dy;
             filltriangle(pTri[0],pTri[1],pTri[3], color);
             filltriangle(pTri[0],pTri[2],pTri[3], color);
-            #else // old slower method
-            // Draw with a lot of overlapping circles
-            int dx = abs(p2.x-p1.x), sx = p1.x<p2.x ? 1 : -1;
-            int dy = abs(p2.y-p1.y), sy = p1.y<p2.y ? 1 : -1;
-            int err = (dx>dy ? dx : -dy)/2, e2;
-
-            for (;;) {
-                fillcircle(p1.x, p1.y, thickness/2, color);
-                if (p1.x==p2.x && p1.y==p2.y)
-                    break;
-                e2 = err;
-                if (e2 >-dx)
-                    { err -= dy; p1.x += sx; }
-                if (e2 < dy)
-                    { err += dx; p1.y += sy; }
-            }
-            #endif
         }
     }
     return noerror;
@@ -1930,8 +2051,8 @@
     RetCode_t ret = noerror;
     PERFORMANCE_RESET;
     // check for bad_parameter
-    if (x1 < 0 || x1 >= screenwidth || x2 < 0 || x2 >= screenwidth
-    || y1 < 0 || y1 >= screenheight || y2 < 0 || y2 >= screenheight) {
+    if (x1 < 0 || x1 >= virt_screenwidth || x2 < 0 || x2 >= virt_screenwidth
+    || y1 < 0 || y1 >= virt_screenheight || y2 < 0 || y2 >= virt_screenheight) {
         ret = bad_parameter;
     } else {
         if (x1 == x2 && y1 == y2) {
@@ -1941,10 +2062,27 @@
         } else if (y1 == y2) {
             line(x1, y1, x2, y2);
         } else {
-            WriteCommandW(RA8875_DLHSR0, x1);
-            WriteCommandW(RA8875_DLVSR0, y1);
-            WriteCommandW(RA8875_DLHER0, x2);
-            WriteCommandW(RA8875_DLVER0, y2);
+            switch (screen_orientation) {
+            case rotate_0:
+            case rotate_180:
+                WriteCommandW(RA8875_DLHSR0, x1);
+                WriteCommandW(RA8875_DLVSR0, y1);
+                WriteCommandW(RA8875_DLHER0, x2);
+                WriteCommandW(RA8875_DLVER0, y2);
+                break;
+            case rotate_90:
+            case rotate_270:
+                WriteCommandW(RA8875_DLHSR0, y1);
+                WriteCommandW(RA8875_DLVSR0, x1);
+                WriteCommandW(RA8875_DLHER0, y2);
+                WriteCommandW(RA8875_DLVER0, x2);
+                break;
+            case invalid:
+                REGISTERPERFORMANCE(PRF_DRAWRECTANGLE);
+                ret = bad_parameter;
+                return ret;
+                //break;
+            }
             unsigned char drawCmd = 0x10;   // Rectangle
             if (fillit == FILL)
                 drawCmd |= 0x20;
@@ -1997,8 +2135,8 @@
 
     INFO("roundrect()");
     PERFORMANCE_RESET;
-    if (x1 < 0 || x1 >= screenwidth || x2 < 0 || x2 >= screenwidth
-    || y1 < 0 || y1 >= screenheight || y2 < 0 || y2 >= screenheight) {
+    if (x1 < 0 || x1 >= virt_screenwidth || x2 < 0 || x2 >= virt_screenwidth
+    || y1 < 0 || y1 >= virt_screenheight || y2 < 0 || y2 >= virt_screenheight) {
         ret = bad_parameter;
     } else if (x1 > x2 || y1 > y2 || (radius1 > (x2-x1)/2) || (radius2 > (y2-y1)/2) ) {
         ret = bad_parameter;
@@ -2009,12 +2147,30 @@
     } else if (y1 == y2) {
         line(x1, y1, x2, y2);
     } else {
-        WriteCommandW(RA8875_DLHSR0, x1);
-        WriteCommandW(RA8875_DLVSR0, y1);
-        WriteCommandW(RA8875_DLHER0, x2);
-        WriteCommandW(RA8875_DLVER0, y2);
-        WriteCommandW(RA8875_ELLA0, radius1);
-        WriteCommandW(RA8875_ELLB0, radius2);
+        switch (screen_orientation) {
+        case rotate_0:
+        case rotate_180:
+            WriteCommandW(RA8875_DLHSR0, x1);
+            WriteCommandW(RA8875_DLVSR0, y1);
+            WriteCommandW(RA8875_DLHER0, x2);
+            WriteCommandW(RA8875_DLVER0, y2);
+            WriteCommandW(RA8875_ELLA0, radius1);
+            WriteCommandW(RA8875_ELLB0, radius2);
+            break;
+        case rotate_90:
+        case rotate_270:
+            WriteCommandW(RA8875_DLHSR0, y1);
+            WriteCommandW(RA8875_DLVSR0, x1);
+            WriteCommandW(RA8875_DLHER0, y2);
+            WriteCommandW(RA8875_DLVER0, x2);
+            WriteCommandW(RA8875_ELLA0, radius2);
+            WriteCommandW(RA8875_ELLB0, radius1);
+            break;
+        case invalid:
+            REGISTERPERFORMANCE(PRF_DRAWROUNDEDRECTANGLE);
+            return bad_parameter;
+            //break;
+        }
         // Should not need this...
         WriteCommandW(RA8875_DEHR0, 0);
         WriteCommandW(RA8875_DEVR0, 0);
@@ -2051,8 +2207,8 @@
 {
     RetCode_t ret;
 
-    if (x1 < 0 || x1 >= screenwidth || x2 < 0 || x2 >= screenwidth || x3 < 0 || x3 >= screenwidth
-    || y1 < 0 || y1 >= screenheight || y2 < 0 || y2 >= screenheight || y3 < 0 || y3 >= screenheight)
+    if (x1 < 0 || x1 >= virt_screenwidth || x2 < 0 || x2 >= virt_screenwidth || x3 < 0 || x3 >= virt_screenwidth
+    || y1 < 0 || y1 >= virt_screenheight || y2 < 0 || y2 >= virt_screenheight || y3 < 0 || y3 >= virt_screenheight)
         ret = bad_parameter;
     foreground(color);
     ret = triangle(x1,y1,x2,y2,x3,y3,fillit);
@@ -2081,12 +2237,30 @@
     if (x1 == x2 && y1 == y2 && x1 == x3 && y1 == y3) {
         pixel(x1, y1);
     } else {
-        WriteCommandW(RA8875_DLHSR0, x1);
-        WriteCommandW(RA8875_DLVSR0, y1);
-        WriteCommandW(RA8875_DLHER0, x2);
-        WriteCommandW(RA8875_DLVER0, y2);
-        WriteCommandW(RA8875_DTPH0, x3);
-        WriteCommandW(RA8875_DTPV0, y3);
+        switch (screen_orientation) {
+        case rotate_0:
+        case rotate_180:
+            WriteCommandW(RA8875_DLHSR0, x1);
+            WriteCommandW(RA8875_DLVSR0, y1);
+            WriteCommandW(RA8875_DLHER0, x2);
+            WriteCommandW(RA8875_DLVER0, y2);
+            WriteCommandW(RA8875_DTPH0, x3);
+            WriteCommandW(RA8875_DTPV0, y3);
+            break;
+        case rotate_90:
+        case rotate_270:
+            WriteCommandW(RA8875_DLHSR0, y1);
+            WriteCommandW(RA8875_DLVSR0, x1);
+            WriteCommandW(RA8875_DLHER0, y2);
+            WriteCommandW(RA8875_DLVER0, x2);
+            WriteCommandW(RA8875_DTPH0, y3);
+            WriteCommandW(RA8875_DTPV0, x3);
+            break;
+        case invalid:
+            REGISTERPERFORMANCE(PRF_DRAWTRIANGLE);
+            return bad_parameter;
+            //break;
+        }
         unsigned char drawCmd = 0x01;       // Triangle
         if (fillit == FILL)
             drawCmd |= 0x20;
@@ -2139,41 +2313,34 @@
     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;
 
     INFO("circle");
     PERFORMANCE_RESET;
-    #if 0
-    loc_t t;
-    SetTextCursor(0,10);
-    printf("Circle(%3d,%3d) => ", x,y);
-    switch (screen_orientation) {
-        default:
-        case rotate_0:
-            break;
-        case rotate_90:
-            t = x;
-            x = y;
-            y = t;
-            break;
-        case rotate_180:
-            break;
-        case rotate_270:
-            break;
-    }
-    printf("  => (%3d,%3d)\r\n", x,y);
-    #endif
     if ((x - radius) < 0 || (x + radius) > width()
     || (y - radius) < 0 || (y + radius) > height()) {
         ret = bad_parameter;
     } else if (radius == 1) {
         pixel(x,y);
     } else {
-        WriteCommandW(RA8875_DCHR0, x);
-        WriteCommandW(RA8875_DCVR0, y);
+        switch (screen_orientation) {
+        case rotate_0:
+        case rotate_180:
+            WriteCommandW(RA8875_DCHR0, x);
+            WriteCommandW(RA8875_DCVR0, y);
+            break;
+        case rotate_90:
+        case rotate_270:
+            WriteCommandW(RA8875_DCHR0, y);
+            WriteCommandW(RA8875_DCVR0, x);
+            break;
+        case invalid:
+            REGISTERPERFORMANCE(PRF_DRAWCIRCLE);
+            return bad_parameter;
+            //break;
+        }
         WriteCommand(RA8875_DCRR, radius & 0xFF);
         unsigned char drawCmd = 0x00;       // Circle
         if (fillit == FILL)
@@ -2210,14 +2377,28 @@
 
     INFO("ellipse");
     PERFORMANCE_RESET;
-    if ((x - radius1) < 0 || (x + radius1) > screenwidth
-    || (y - radius2) < 0 || (y + radius2) > screenheight) {
+    if ((x - radius1) < 0 || (x + radius1) > virt_screenwidth
+    || (y - radius2) < 0 || (y + radius2) > virt_screenheight) {
         ret = bad_parameter;
     } else if (radius1 == 1 && radius2 == 1) {
         pixel(x, y);
     } else {
-        WriteCommandW(RA8875_DEHR0, x);
-        WriteCommandW(RA8875_DEVR0, y);
+        switch (screen_orientation) {
+        case rotate_0:
+        case rotate_180:
+            WriteCommandW(RA8875_DEHR0, x);
+            WriteCommandW(RA8875_DEVR0, y);
+            break;
+        case rotate_90:
+        case rotate_270:
+            WriteCommandW(RA8875_DEHR0, y);
+            WriteCommandW(RA8875_DEVR0, x);
+            break;
+        case invalid:
+            REGISTERPERFORMANCE(PRF_DRAWELLIPSE);
+            return bad_parameter;
+            //break;
+        }
         WriteCommandW(RA8875_ELLA0, radius1);
         WriteCommandW(RA8875_ELLB0, radius2);
         unsigned char drawCmd = 0x00;   // Ellipse
@@ -2363,45 +2544,52 @@
         extFontWidth = totalWidth / (lastChar - firstChar);
         INFO("Font Metrics: Avg W: %2d, H: %2d, First:%d, Last:%d", extFontWidth, extFontHeight, firstChar, lastChar);
     }
-    SetTextCursor(GetTextCursor_X(), GetTextCursor_Y());  // soft-font cursor -> hw cursor
+    SetTextCursor(GetTextCursor());  // soft-font cursor -> hw cursor
     font = _font;
     return GraphicsDisplay::SelectUserFont(_font);
 }
 
-RetCode_t RA8875::background(color_t color)
+color_t RA8875::background(color_t color)
 {
+    color_t oldColor = GetBackColor();
     GraphicsDisplay::background(color);
-    return _writeColorTrio(0x60, color);
+    _writeColorTrio(0x60, color);
+    return oldColor;
 }
 
 
-RetCode_t RA8875::background(unsigned char r, unsigned char g, unsigned char b)
+color_t RA8875::background(unsigned char r, unsigned char g, unsigned char b)
 {
-    background(RGB(r,g,b));
-    return noerror;
+    return background(RGB(r,g,b));
 }
 
-
-RetCode_t RA8875::foreground(color_t color)
+color_t RA8875::GetBackColor(void)
 {
-    GraphicsDisplay::foreground(color);
-    return _writeColorTrio(0x63, color);
+    return _readColorTrio(0x60);
 }
 
 
-RetCode_t RA8875::foreground(unsigned char r, unsigned char g, unsigned char b)
+color_t RA8875::foreground(color_t color)
 {
-    foreground(RGB(r,g,b));
-    return noerror;
+    color_t oldColor = GetForeColor();
+    GraphicsDisplay::foreground(color);
+    _writeColorTrio(0x63, color);
+    return oldColor;
 }
 
 
+color_t RA8875::foreground(unsigned char r, unsigned char g, unsigned char b)
+{
+    return foreground(RGB(r,g,b));
+}
+
 color_t RA8875::GetForeColor(void)
 {
     return _readColorTrio(0x63);
 }
 
 
+
 color_t RA8875::DOSColor(int i)
 {
     const color_t colors[16] = {
@@ -2517,10 +2705,10 @@
     color_t * pixelBuffer2 = NULL;
 
     INFO("(%d,%d)-(%d,%d)x%d", x,y,w,h,bitsPerPixel);
-    if (x >= 0 && x < screenwidth
-            && y >= 0 && y < screenheight
-            && w > 0 && x + w <= screenwidth
-            && h > 0 && y + h <= screenheight) {
+    if (x >= 0 && x < virt_screenwidth
+            && y >= 0 && y < virt_screenheight
+            && w > 0 && x + w <= virt_screenwidth
+            && h > 0 && y + h <= virt_screenheight) {
         BMP_Header.bfType = BF_TYPE;
         BMP_Header.bfReserved1 = 0;
         BMP_Header.bfReserved2 = 0;
@@ -2532,14 +2720,14 @@
             case 8:
             default:
                 BMP_Header.bfOffBits = sizeof(BMP_Header) + sizeof(BMP_Info) + sizeof(WebColorPalette);
-                INFO("Initial Offset to Bitstream %X", BMP_Header.bfOffBits);
+                INFO("Initial Offset to Bitstream %lX", BMP_Header.bfOffBits);
                 //if (BMP_Header.bfOffBits & 0x03) {
                 //    BMP_Header.bfOffBits += (4 - (BMP_Header.bfOffBits & 0x03));
                 //}
                 BMP_Header.bfSize = (h * RoundUp(w * 1,4)) + BMP_Header.bfOffBits;
                 break;
         }
-        INFO("Offset to Bitstream %X", BMP_Header.bfOffBits);
+        INFO("Offset to Bitstream %lX", BMP_Header.bfOffBits);
 
         // Bytes in the line buffer
         int lineBufSize = RoundUp(((bitsPerPixel == 24) ? 3 : 1) * w, 4);
@@ -2601,15 +2789,15 @@
         privateCallback(OPEN, (uint8_t *)&BMP_Header.bfSize, 4);
 
         // Be optimistic - don't check for errors.
-        HexDump("BMP_Header", (uint8_t *)&BMP_Header, sizeof(BMP_Header));
+        //HexDump("BMP_Header", (uint8_t *)&BMP_Header, sizeof(BMP_Header));
         //fwrite(&BMP_Header, sizeof(char), sizeof(BMP_Header), Image);
         privateCallback(WRITE, (uint8_t *)&BMP_Header, sizeof(BMP_Header));
 
-        HexDump("BMP_Info", (uint8_t *)&BMP_Info, sizeof(BMP_Info));
+        //HexDump("BMP_Info", (uint8_t *)&BMP_Info, sizeof(BMP_Info));
         //fwrite(&BMP_Info, sizeof(char), sizeof(BMP_Info), Image);
         privateCallback(WRITE, (uint8_t *)&BMP_Info, sizeof(BMP_Info));
         if (bitsPerPixel != 24) {
-            HexDump("Palette", (uint8_t *)&WebColorPalette, sizeof(WebColorPalette));
+            //HexDump("Palette", (uint8_t *)&WebColorPalette, sizeof(WebColorPalette));
             //fwrite(&WebColorPalette, sizeof(char), sizeof(WebColorPalette), Image);
             privateCallback(WRITE, (uint8_t *)&WebColorPalette, sizeof(WebColorPalette));
             if (0 && sizeof(WebColorPalette) % 4) {
@@ -2620,7 +2808,6 @@
         }
         //color_t transparency = GetBackgroundTransparencyColor();
         LayerMode_T ltpr0 = GetLayerMode();
-
         uint16_t prevLayer = GetDrawingLayer();
         // If only one of the layers is visible, select that layer
         switch(ltpr0) {
@@ -2640,10 +2827,10 @@
             if (idle_callback && h >= 1) {
                 (*idle_callback)(progress, (h - 1 - j) * 100 / (h - 1));
             }
-
             if (ltpr0 >= 2)             // Need to combine the layers...
                 SelectDrawingLayer(0);  // so read layer 0 first
             // Read one line of pixels to a local buffer
+            INFO("x,y %d,%d", x, y + j);
             if (getPixelStream(pixelBuffer, w, x,y+j) != noerror) {
                 ERR("getPixelStream error, and no recovery handler...");
             }
@@ -2698,9 +2885,9 @@
                         break;
                 }
             }
-            //if (j == h - 1) {
-            //    HexDump("Line", lineBuffer, lineBufSize);
-            //}
+            if (j == h - 1) {
+                HexDump("Line", lineBuffer, lineBufSize);
+            }
             // Write to disk
             privateCallback(WRITE, (uint8_t *)lineBuffer, lineBufSize);
         }
@@ -2730,11 +2917,11 @@
     color_t * pixelBuffer = NULL;
     color_t * pixelBuffer2 = NULL;
 
-    INFO("(%d,%d)-(%d,%d)x%d %s", x,y,w,h,bitsPerPixel,Name_BMP);
-    if (x >= 0 && x < screenwidth
-            && y >= 0 && y < screenheight
-            && w > 0 && x + w <= screenwidth
-            && h > 0 && y + h <= screenheight) {
+    //INFO("(%d,%d)-(%d,%d)x%d %s", x,y,w,h,bitsPerPixel,Name_BMP);
+    if (x >= 0 && x < virt_screenwidth
+            && y >= 0 && y < virt_screenheight
+            && w > 0 && x + w <= virt_screenwidth
+            && h > 0 && y + h <= virt_screenheight) {
         BMP_Header.bfType = BF_TYPE;
         BMP_Header.bfReserved1 = 0;
         BMP_Header.bfReserved2 = 0;
@@ -2746,18 +2933,18 @@
             case 8:
             default:
                 BMP_Header.bfOffBits = sizeof(BMP_Header) + sizeof(BMP_Info) + sizeof(WebColorPalette);
-                INFO("Initial Offset to Bitstream %X", BMP_Header.bfOffBits);
+                //INFO("Initial Offset to Bitstream %lX", BMP_Header.bfOffBits);
                 //if (BMP_Header.bfOffBits & 0x03) {
                 //    BMP_Header.bfOffBits += (4 - (BMP_Header.bfOffBits & 0x03));
                 //}
                 BMP_Header.bfSize = (h * RoundUp(w * 1,4)) + BMP_Header.bfOffBits;
                 break;
         }
-        INFO("Offset to Bitstream %X", BMP_Header.bfOffBits);
+        //INFO("Offset to Bitstream %lX", BMP_Header.bfOffBits);
 
         // Bytes in the line buffer
         int lineBufSize = RoundUp(((bitsPerPixel == 24) ? 3 : 1) * w, 4);
-        INFO("LineBufSize: %d", lineBufSize);
+        //INFO("LineBufSize: %d", lineBufSize);
 
         BMP_Info.biSize = sizeof(BMP_Info);
         BMP_Info.biWidth = w;
@@ -2824,14 +3011,14 @@
         }
 
         // Be optimistic - don't check for errors.
-        HexDump("BMP_Header", (uint8_t *)&BMP_Header, sizeof(BMP_Header));
+        //HexDump("BMP_Header", (uint8_t *)&BMP_Header, sizeof(BMP_Header));
         fwrite(&BMP_Header, sizeof(char), sizeof(BMP_Header), Image);
 
-        HexDump("BMP_Info", (uint8_t *)&BMP_Info, sizeof(BMP_Info));
+        //HexDump("BMP_Info", (uint8_t *)&BMP_Info, sizeof(BMP_Info));
         fwrite(&BMP_Info, sizeof(char), sizeof(BMP_Info), Image);
 
         if (bitsPerPixel != 24) {
-            HexDump("Palette", (uint8_t *)&WebColorPalette, sizeof(WebColorPalette));
+            //HexDump("Palette", (uint8_t *)&WebColorPalette, sizeof(WebColorPalette));
             fwrite(&WebColorPalette, sizeof(char), sizeof(WebColorPalette), Image);
             if (0 && sizeof(WebColorPalette) % 4) {
                 const uint8_t padd[] = { 0, 0, 0 };
@@ -2864,6 +3051,7 @@
 
             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...");
@@ -2874,7 +3062,7 @@
                     ERR("getPixelStream error, and no recovery handler...");
                 }
             }
-            INFO("Line: %3d", j);
+            //INFO("Line: %3d", j);
             //HexDump("Raster", (uint8_t *)pixelBuffer, w * sizeof(color_t));
             // Convert the local buffer to RGBQUAD format
             int lb = 0;
@@ -2934,7 +3122,7 @@
         if (pixelBuffer)
             swFree(pixelBuffer);
         swFree(lineBuffer);
-        INFO("Image closed");
+        //INFO("Image closed");
         return noerror;
     } else {
         return bad_parameter;