This is the David Smart RA8875 Library with mods for working with FRDM-K64F

Revision:
190:3132b7dfad82
Parent:
186:910fc2335c45
Child:
191:0fad2e45e196
--- a/RA8875.cpp	Thu Sep 19 21:45:18 2019 +0000
+++ b/RA8875.cpp	Sat Sep 21 17:30:00 2019 +0000
@@ -23,9 +23,9 @@
 // INFO("Stuff to show %d", var); // new-line is automatically appended
 //
 #if (defined(DEBUG) && !defined(TARGET_LPC11U24))
-#define INFO(x, ...) std::printf("[INF %s %4d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
-#define WARN(x, ...) std::printf("[WRN %s %4d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
-#define ERR(x, ...)  std::printf("[ERR %s %4d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
+#define INFO(x, ...) std::printf("[INF %s %4d] " x "\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
+#define WARN(x, ...) std::printf("[WRN %s %4d] " x "\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
+#define ERR(x, ...)  std::printf("[ERR %s %4d] " x "\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
 static void HexDump(const char * title, const uint8_t * p, int count)
 {
     int i;
@@ -151,13 +151,13 @@
     {0xFF,0xCC,0x00,0xFF}, {0xFF,0xCC,0x33,0xFF}, {0xFF,0xCC,0x66,0xFF}, {0xFF,0xCC,0x99,0xFF}, {0xFF,0xCC,0xCC,0xFF}, {0xFF,0xCC,0xFF,0xFF},
     {0xFF,0xFF,0x00,0xFF}, {0xFF,0xFF,0x33,0xFF}, {0xFF,0xFF,0x66,0xFF}, {0xFF,0xFF,0x99,0xFF}, {0xFF,0xFF,0xCC,0xFF}, {0xFF,0xFF,0xFF,0xFF},
 
-    {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, 
-    {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, 
-    {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, 
-    {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, 
-    {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, 
-    {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, 
-    {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, 
+    {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF},
+    {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF},
+    {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF},
+    {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF},
+    {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF},
+    {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF},
+    {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF},
 };
 
 #define sqr(a) ((a) * (a))
@@ -185,7 +185,7 @@
 
 // Non-Touch, or Resistive Touch when later initialized that way
 //
-RA8875::RA8875(PinName mosi, PinName miso, PinName sclk, PinName csel, PinName reset, 
+RA8875::RA8875(PinName mosi, PinName miso, PinName sclk, PinName csel, PinName reset,
     const char *name)
     : GraphicsDisplay(name)
     , spi(mosi, miso, sclk)
@@ -201,8 +201,8 @@
 
 // Touch, based on FT5206 Controller Chip
 //
-RA8875::RA8875(PinName mosi, PinName miso, PinName sclk, PinName csel, PinName reset, 
-    PinName sda, PinName scl, PinName irq, const char * name) 
+RA8875::RA8875(PinName mosi, PinName miso, PinName sclk, PinName csel, PinName reset,
+    PinName sda, PinName scl, PinName irq, const char * name)
     : GraphicsDisplay(name)
     , spi(mosi, miso, sclk)
     , cs(csel)
@@ -213,14 +213,14 @@
     m_irq = new InterruptIn(irq);
     m_i2c = new I2C(sda, scl);
     INFO("m_i2c = %p", m_i2c);
-    
+
     // Cap touch panel config
     touchInfo = (touchInfo_T *)malloc(FT5206_TOUCH_POINTS * sizeof(touchInfo_T));
     if (touchInfo)
         useTouchPanel = TP_FT5206;
     m_addr = (FT5206_I2C_ADDRESS << 1);
     m_i2c->frequency(FT5206_I2C_FREQUENCY);
-    
+
     // Interrupt
     m_irq->mode(PullUp);
     #if MBED_VERSION >= MBED_ENCODE_VERSION(5,8,0)
@@ -239,8 +239,8 @@
 
 // Touch, based on GSL1680 Controller Chip
 //
-RA8875::RA8875(PinName mosi, PinName miso, PinName sclk, PinName csel, PinName reset, 
-    PinName sda, PinName scl, PinName wake, PinName irq, const char * name) 
+RA8875::RA8875(PinName mosi, PinName miso, PinName sclk, PinName csel, PinName reset,
+    PinName sda, PinName scl, PinName wake, PinName irq, const char * name)
     : GraphicsDisplay(name)
     , spi(mosi, miso, sclk)
     , cs(csel)
@@ -248,7 +248,7 @@
 {
     INFO("RA8875");
     InitAllMemberVars();
-    
+
     m_irq = new InterruptIn(irq);
     m_i2c = new I2C(sda, scl);
 
@@ -315,6 +315,7 @@
     cursor_x = 0;
     cursor_y = 0;
     _printFH = NULL;
+    roundCap = false;
     screen_orientation = normal;
 #ifdef PERF_METRICS
     ClearPerformance();
@@ -429,7 +430,7 @@
 RetCode_t RA8875::Reset(void)
 {
     RetCode_t ret;
-    
+
     #if 0
     if (res != (PinName)NC) {
         res = 0;                            // Active low - assert reset
@@ -464,10 +465,10 @@
 RetCode_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;
-    
+
     mwcr1 &= ~0x01; // remove the current layer
     if (screenwidth >= 800 && screenheight >= 480 && screenbpp > 8) {
         layer = 0;
@@ -487,7 +488,7 @@
 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(RA8875_LTPR0, ltpr0 | (mode & 0x7));
         return noerror;
@@ -517,7 +518,7 @@
 color_t RA8875::GetBackgroundTransparencyColor(void)
 {
     RGBQUAD q;
-    
+
     q.rgbRed = ReadCommand(0x67);
     q.rgbGreen = ReadCommand(0x68);
     q.rgbBlue = ReadCommand(0x69);
@@ -573,7 +574,7 @@
     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.
@@ -646,7 +647,7 @@
 void RA8875::ClearPerformance()
 {
     int i;
-    
+
     for (i=0; i<METRICCOUNT; i++)
         metrics[i] = 0;
     idletime_usec = 0;
@@ -673,7 +674,7 @@
 void RA8875::ReportPerformance(Serial & pc)
 {
     int i;
-    
+
     pc.printf("\r\nPerformance Metrics\r\n");
     for (i=0; i<METRICCOUNT; i++) {
         pc.printf("%10d uS %s\r\n", metrics[i], metricsName[i]);
@@ -687,6 +688,44 @@
 #endif
 
 
+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;
+    switch (h) {
+        case left:
+        default:
+            newRect.p1.x = inRect.p1.x;
+            newRect.p2.x = newRect.p1.x + width;
+            break;
+        case center:
+            newRect.p1.x = (inRect.p1.x + inRect.p2.x + 1) / 2 - width / 2;
+            newRect.p2.x = newRect.p1.x + width;
+            break;
+        case right:
+            newRect.p1.x = inRect.p2.x - width;
+            newRect.p2.x = newRect.p1.x + width;
+            break;
+    }
+    switch (v) {
+        case top:
+        default:
+            newRect.p1.y = inRect.p1.y;
+            newRect.p2.y = newRect.p1.y + height;
+            break;
+        case middle:
+            newRect.p1.y = (inRect.p1.y + inRect.p2.y + 1) / 2 - height / 2;
+            newRect.p2.y = newRect.p1.y + height;
+            break;
+        case bottom:
+            newRect.p1.y = inRect.p2.y - height;
+            newRect.p2.y = newRect.p1.y + height;
+            break;
+    }
+    return newRect;
+}
+
+
 bool RA8875::Intersect(rect_t rect, point_t p)
 {
     if (p.x >= min(rect.p1.x, rect.p2.x) && p.x <= max(rect.p1.x, rect.p2.x)
@@ -728,7 +767,7 @@
 {
     if (Intersect(*pRect1, *pRect2)) {
         rect_t iSect;
-        
+
         iSect.p1.x = max(min(pRect1->p1.x,pRect1->p2.x),min(pRect2->p1.x,pRect2->p2.x));
         iSect.p1.y = max(min(pRect1->p1.y,pRect1->p2.y),min(pRect2->p1.y,pRect2->p2.y));
         iSect.p2.x = min(max(pRect1->p1.x,pRect1->p2.x),max(pRect2->p1.x,pRect2->p2.x));
@@ -899,7 +938,7 @@
 {
     color_t c16;
     color_t temp = (color_t)c8;
-    
+
     c16 = ((temp & 0xE0) << 8)
         | ((temp & 0xC0) << 5)
         | ((temp & 0x1C) << 6)
@@ -914,14 +953,14 @@
 RetCode_t RA8875::_writeColorTrio(uint8_t regAddr, color_t color)
 {
     RetCode_t rt = noerror;
-    
+
     if (screenbpp == 16) {
         WriteCommand(regAddr+0, (color>>11));                  // BGCR0
         WriteCommand(regAddr+1, (unsigned char)(color>>5));    // BGCR1
         rt = WriteCommand(regAddr+2, (unsigned char)(color));       // BGCR2
     } else {
         uint8_t r, g, b;
-        
+
         // RRRR RGGG GGGB BBBB      RGB
         // RRR   GGG    B B
         r = (uint8_t)((color) >> 13);
@@ -938,7 +977,7 @@
 {
     color_t color;
     uint8_t r, g, b;
-    
+
     r = ReadCommand(regAddr+0);
     g = ReadCommand(regAddr+1);
     b = ReadCommand(regAddr+2);
@@ -1018,6 +1057,12 @@
     return screenbpp;
 }
 
+bool RA8875::SetWordWrap(bool _wordwrap) {
+    bool prevWrap = wordwrap;
+    wordwrap = _wordwrap;
+    return prevWrap;
+}
+
 RetCode_t RA8875::SetTextCursor(point_t p)
 {
     return SetTextCursor(p.x, p.y);
@@ -1036,7 +1081,7 @@
 point_t RA8875::GetTextCursor(void)
 {
     point_t p;
-    
+
     p.x = GetTextCursor_X();
     p.y = GetTextCursor_Y();
     return p;
@@ -1045,7 +1090,7 @@
 loc_t RA8875::GetTextCursor_Y(void)
 {
     loc_t y;
-    
+
     if (font == NULL)
         y = ReadCommand(0x2C) | (ReadCommand(0x2D) << 8);
     else
@@ -1058,7 +1103,7 @@
 loc_t RA8875::GetTextCursor_X(void)
 {
     loc_t x;
-    
+
     if (font == NULL)
         x = ReadCommand(0x2A) | (ReadCommand(0x2B) << 8);
     else
@@ -1122,7 +1167,7 @@
     uint8_t fncr1Val = ReadCommand(0x22);
     uint8_t dpcrVal = ReadCommand(0x20);
     RetCode_t r;
-    
+
     screen_orientation = angle;
     fncr1Val &= ~0x10;      // remove the old font rotation bit
     dpcrVal &= ~0x0C;       // remove the old scan direction bits
@@ -1165,7 +1210,7 @@
     if (hScale >= 1 && hScale <= 4 &&
             vScale >= 1 && vScale <= 4) {
         uint8_t fncr1Val = ReadCommand(0x22);
-        
+
         fncr1Val &= 0x10;      // remove all except the font rotation bit
         if (alignment == align_full)
             fncr1Val |= 0x80;
@@ -1179,6 +1224,19 @@
     }
 }
 
+fill_t RA8875::SetTextFontFill(fill_t fillit)
+{
+    fill_t prevFill = FILL;
+    uint8_t fncr1Val = ReadCommand(0x22);
+
+    if (fncr1Val & 0x40)
+        prevFill = NOFILL;
+    fncr1Val &= ~0x40;
+    if (fillit == NOFILL)
+        fncr1Val |= 0x40;
+    WriteCommand(RA8875_FNCR1, fncr1Val);
+    return prevFill;
+}
 
 RetCode_t RA8875::SetTextFontSize(RA8875::HorizontalScale hScale, RA8875::VerticalScale vScale)
 {
@@ -1204,12 +1262,34 @@
     unsigned char reg = ReadCommand(0x22);
 
     if (hScale)
-        *hScale = 1 + (reg >> 2) & 0x03;
+        *hScale = 1 + ((reg >> 2) & 0x03);
     if (vScale)
-        *vScale = 1 + reg & 0x03;
+        *vScale = 1 + (reg & 0x03);
     return noerror;
 }
 
+dim_t RA8875::GetTextWidth(const char * text, bool charOnly)
+{
+    if (font == NULL) {
+        if (charOnly)
+            return fontwidth() * fontScaleX;
+        else
+            return fontwidth() * strlen(text) * fontScaleX;
+    } else {
+        dim_t width = 0;
+
+        while (*text) {
+            dim_t cWidth;
+            if (getCharMetrics(*text, &cWidth, NULL))
+                width += cWidth;
+            if (charOnly)
+                break;
+            text++;
+        }
+        return width * fontScaleX;
+    }
+}
+
 int RA8875::_putc(int c)
 {
     if (font == NULL) {
@@ -1219,8 +1299,8 @@
     }
 }
 
-
-
+// Questions to ponder -
+// - if we choose to wrap to the next line, because the character won't fit on the current line,
 // Questions to ponder -
 // - if we choose to wrap to the next line, because the character won't fit on the current line,
 //      should it erase the space to the width of the screen (in case there is leftover junk there)?
@@ -1237,10 +1317,10 @@
         } 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, 
+            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);
             if (charRecord) {
@@ -1326,8 +1406,59 @@
     if (font == NULL) {
         WriteCommand(RA8875_MWCR0,0x80);    // Put in Text mode if internal font
     }
-    if (*string != '\0') {
-        while (*string) {           // @TODO calling individual _putc is slower... optimizations?
+    point_t cursor = GetTextCursor();
+    while (*string) {           // @TODO calling individual _putc is slower... optimizations?
+        if (wordwrap) {
+            const char * p = string;
+            const char * pSpace = NULL;
+            dim_t txtPos;
+            bool newLineNeeded = false;
+
+            cursor = GetTextCursor();
+            txtPos = cursor.x;
+            INFO("(%d,%d) string: '%s'\r\n", cursor.x, cursor.y, string);
+            // find what fits in the window
+            do {
+                if (*p == ' ')
+                    pSpace = p;
+                if (*p == '\r') {
+                    pSpace = p;
+                    break;
+                }
+                if (*p == '\n') {
+                    break;
+                }
+                dim_t cWidth = GetTextWidth(p, true);
+                if (txtPos + cWidth < windowrect.p2.x) {
+                    txtPos += cWidth;
+                } else {
+                    newLineNeeded = true;
+                    break;
+                }
+                INFO("+ %c width %d, ttl Width %d\r\n", *p, cWidth, txtPos);
+                p++;
+            } while (*p);
+            INFO(" do { } while();\r\n");
+            if (*p != ' ' && pSpace) {
+                p = pSpace;
+            }
+            INFO("txtPos: %d < windowrect.p2.x: %d\r\n", txtPos, windowrect.p2.x);
+            if (txtPos < windowrect.p2.x) {
+                while (*string && string <= p) {
+                    _putc(*string++);
+                }
+            }
+            while (*string == ' ')
+                string++;
+            if (newLineNeeded) {
+                cursor.y += fontheight();
+                SetTextCursor(cursor);
+                INFO("\r\n");
+            }
+            INFO("### '%s'\r\n\r\n", string);
+            // if != ' ', find ' ', accumulating width along the way
+            // if the width fits, print the chars
+        } else {
             _putc(*string++);
         }
     }
@@ -1349,7 +1480,7 @@
 point_t RA8875::GetGraphicsCursor(void)
 {
     point_t p;
-    
+
     p.x = ReadCommandW(0x46);
     p.y = ReadCommandW(0x48);
     return p;
@@ -1492,10 +1623,10 @@
 // With a font scale Y = 2, a pixel stream is "abcdefg..."
 //                                            "abcdefg..."
 //
-RetCode_t RA8875::booleanStream(loc_t x, loc_t y, dim_t w, dim_t h, const uint8_t * boolStream) 
+RetCode_t RA8875::booleanStream(loc_t x, loc_t y, dim_t w, dim_t h, const uint8_t * boolStream)
 {
     PERFORMANCE_RESET;
-    const uint8_t * rowStream;
+    const uint8_t * rowStream = boolStream;
     rect_t restore = windowrect;
     window(x, y, w * fontScaleX, h * fontScaleY);       // Scale from font scale factors
     SetGraphicsCursor(x, y);
@@ -1506,12 +1637,12 @@
         for (int dy=0; dy<fontScaleY; dy++) {           // Vertical Font Scale Factor
             uint8_t pixels = w;
             uint8_t bitmask = 0x01;
-            rowStream = boolStream;        
+            rowStream = boolStream;
             while (pixels) {
                 uint8_t byte = *rowStream;
                 //INFO("byte, mask: %02X, %02X", byte, bitmask);
                 color_t c = (byte & bitmask) ? _foreground : _background;
-                
+
                 for (int dx=0; dx<fontScaleX; dx++) {   // Horizontal Font Scale Factor
                     if (screenbpp == 16) {
                         _spiwrite(c >> 8);
@@ -1639,13 +1770,17 @@
     } else {
         if (p1.x == p2.x) {
             // vertical
-            fillcircle(p1, thickness/2, color);
-            fillcircle(p2, thickness/2, color);
+            if (roundCap) {
+                fillcircle(p1, thickness / 2, color);
+                fillcircle(p2, thickness / 2, color);
+            }
             fillrect(p1.x-thickness/2,p1.y, p2.x+thickness/2,p2.y, color);
         } else if (p1.y == p2.y) {
             // horizontal
-            fillcircle(p1, thickness/2, color);
-            fillcircle(p2, thickness/2, color);
+            if (roundCap) {
+                fillcircle(p1, thickness / 2, color);
+                fillcircle(p2, thickness / 2, color);
+            }
             fillrect(p1.x,p1.y-thickness/2, p2.x,p2.y+thickness/2, color);
         } else {
             // some diagonal, drawn rather slowly with filled circles
@@ -1653,8 +1788,10 @@
             //      with 2 triangles. 
             #if 1  // New Faster method
             //Round-caps
-            fillcircle(p1, thickness/2, color);
-            fillcircle(p2, thickness/2, color);
+            if (roundCap) {
+                fillcircle(p1, thickness / 2, color);
+                fillcircle(p2, thickness / 2, color);
+            }
             // Compute the perpendicular points to draw the triangles
             //              +           fillTriangle: p1a,p1b,p2a
             //            /   + p1a                   p1a,p2a,p2b
@@ -1673,7 +1810,7 @@
             slope = -1/slope;
             //centerline
             //line(p1,p2,color);
-            float dx = (thickness/2 / sqrt(thickness/2 + (slope * slope))); 
+            float dx = (thickness/2 / sqrt(thickness/2 + (slope * slope)));
             float dy = slope * dx;
             pTri[0].x = p1.x + dx;
             pTri[0].y = p1.y + dy;
@@ -1690,15 +1827,15 @@
             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) 
+                if (p1.x==p2.x && p1.y==p2.y)
                     break;
                 e2 = err;
-                if (e2 >-dx) 
+                if (e2 >-dx)
                     { err -= dy; p1.x += sx; }
-                if (e2 < dy) 
+                if (e2 < dy)
                     { err += dx; p1.y += sy; }
             }
             #endif
@@ -1708,6 +1845,13 @@
 }
 
 
+bool RA8875::SetEndCap(bool _roundCap) {
+    bool prevCap = roundCap;
+    roundCap = _roundCap;
+    return prevCap;
+}
+
+
 //
 // Rectangle functions all mostly helpers to the basic rectangle function
 //
@@ -1741,7 +1885,7 @@
     RetCode_t ret = noerror;
     PERFORMANCE_RESET;
     // check for bad_parameter
-    if (x1 < 0 || x1 >= screenwidth || x2 < 0 || x2 >= screenwidth 
+    if (x1 < 0 || x1 >= screenwidth || x2 < 0 || x2 >= screenwidth
     || y1 < 0 || y1 >= screenheight || y2 < 0 || y2 >= screenheight) {
         ret = bad_parameter;
     } else {
@@ -1808,7 +1952,7 @@
 
     INFO("roundrect()");
     PERFORMANCE_RESET;
-    if (x1 < 0 || x1 >= screenwidth || x2 < 0 || x2 >= screenwidth 
+    if (x1 < 0 || x1 >= screenwidth || x2 < 0 || x2 >= screenwidth
     || y1 < 0 || y1 >= screenheight || y2 < 0 || y2 >= screenheight) {
         ret = bad_parameter;
     } else if (x1 > x2 || y1 > y2 || (radius1 > (x2-x1)/2) || (radius2 > (y2-y1)/2) ) {
@@ -1954,7 +2098,7 @@
 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
@@ -2021,7 +2165,7 @@
 
     INFO("ellipse");
     PERFORMANCE_RESET;
-    if ((x - radius1) < 0 || (x + radius1) > screenwidth 
+    if ((x - radius1) < 0 || (x + radius1) > screenwidth
     || (y - radius2) < 0 || (y + radius2) > screenheight) {
         ret = bad_parameter;
     } else if (radius1 == 1 && radius2 == 1) {
@@ -2116,7 +2260,7 @@
 RetCode_t RA8875::Backlight_u8(uint8_t brightness)
 {
     static bool is_enabled = false;
-    
+
     if (brightness == 0) {
         WriteCommand(RA8875_P1CR); // Disable the PWM
         WriteData(0x00);
@@ -2165,7 +2309,7 @@
         uint16_t firstChar = _font[3] * 256 + _font[2];
         uint16_t lastChar  = _font[5] * 256 + _font[4];
         uint16_t i;
-        
+
         for (i=firstChar; i<=lastChar; i++) {
             // 8 bytes of preamble to the first level lookup table
             uint16_t offsetToCharLookup = 8 + 4 * (i - firstChar);    // 4-bytes: width(pixels), 16-bit offset from table start, 0
@@ -2279,7 +2423,7 @@
 RetCode_t RA8875::PrintScreen(uint16_t layer, loc_t x, loc_t y, dim_t w, dim_t h, const char *Name_BMP)
 {
     (void)layer;
-    
+
     // AttachPrintHandler(this, RA8875::_printCallback);
     // return PrintScreen(x,y,w,h);
     return PrintScreen(x, y, w, h, Name_BMP);
@@ -2314,7 +2458,7 @@
 
 int RA8875::RoundUp(int value, int roundTo)
 {
-    if (roundTo == 0) 
+    if (roundTo == 0)
         return 0;
     return ((value + roundTo - 1) / roundTo) * roundTo;
 }
@@ -2326,7 +2470,7 @@
     uint8_t * lineBuffer = NULL;
     color_t * pixelBuffer = NULL;
     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
@@ -2367,7 +2511,7 @@
         BMP_Info.biYPelsPerMeter = 0;
         // for 24-bit, there is no palette, so these are zero
         // for 8-bit, there can be up to 256 RGB values in the palette
-        
+
         BMP_Info.biClrUsed = (bitsPerPixel == 24) ? 0 : sizeof(WebColorPalette)/sizeof(WebColorPalette[0]);    // for 8b/pixel
         BMP_Info.biClrImportant = BMP_Info.biClrUsed;
 
@@ -2380,7 +2524,7 @@
         memset(lineBuffer, 0, lineBufSize); // zero-Fill
 
         #define DOUBLEBUF /* one larger buffer instead of two */
-        
+
         #ifdef DOUBLEBUF
         // In the "#else", pixelBuffer2 malloc returns a value, 
         // but is actually causing a failure later. 
@@ -2540,7 +2684,7 @@
     uint8_t * lineBuffer = NULL;
     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
@@ -2581,7 +2725,7 @@
         BMP_Info.biYPelsPerMeter = 0;
         // for 24-bit, there is no palette, so these are zero
         // for 8-bit, there can be up to 256 RGB values in the palette
-        
+
         BMP_Info.biClrUsed = (bitsPerPixel == 24) ? 0 : sizeof(WebColorPalette)/sizeof(WebColorPalette[0]);    // for 8b/pixel
         BMP_Info.biClrImportant = BMP_Info.biClrUsed;
 
@@ -2594,7 +2738,7 @@
         memset(lineBuffer, 0, lineBufSize); // zero-Fill
 
         #define DOUBLEBUF /* one larger buffer instead of two */
-        
+
         #ifdef DOUBLEBUF
         // In the "#else", pixelBuffer2 malloc returns a value, 
         // but is actually causing a failure later. 
@@ -2640,13 +2784,13 @@
 
         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));
             fwrite(&WebColorPalette, sizeof(char), sizeof(WebColorPalette), Image);
             if (0 && sizeof(WebColorPalette) % 4) {
                 const uint8_t padd[] = { 0, 0, 0 };
-                fwrite(&padd, sizeof(char), 
+                fwrite(&padd, sizeof(char),
                     (sizeof(BMP_Header) + sizeof(BMP_Info) + sizeof(WebColorPalette)) % 4, Image);
             }
         }
@@ -2995,7 +3139,7 @@
 
     display.SelectUserFont(BPG_Arial20x20);
     display.puts("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\r\n");
-    
+
     display.SelectUserFont();
 
     display.puts("Normal font again.");
@@ -3381,7 +3525,7 @@
     Timer t;
     int x, y;
     tpMatrix_t calmatrix;
-    
+
     display.background(Black);
     display.foreground(Blue);
     display.cls();