BurstSPI support for improved performance

Fork of RA8875 by David Smart

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers RA8875.cpp Source File

RA8875.cpp

00001 /// RA8875 Display Controller Library.
00002 ///
00003 /// This is being created for a Raio RA8875-based display from buydisplay.com,
00004 /// which is 480 x 272 using a 4-wire SPI interface. Support is provided for
00005 /// both a keypad and a resistive touch-screen.
00006 ///
00007 /// This driver has been fully tested with an 800 x 480 variant (also using
00008 /// 4-wire SPI).
00009 ///
00010 /// 20161106: Updated the initialization to set the various registers based on
00011 ///           the BuyDisplay.com example code. This altered several registers
00012 ///           for the 800x480 display driver.
00013 ///
00014 #include "RA8875.h"
00015 
00016 //#include "Utility.h"            // private memory manager
00017 #ifndef UTILITY_H
00018 #define swMalloc malloc         // use the standard
00019 #define swFree free
00020 #endif
00021 
00022 //#define DEBUG "RAIO"
00023 // ...
00024 // INFO("Stuff to show %d", var); // new-line is automatically appended
00025 //
00026 #if (defined(DEBUG) && !defined(TARGET_LPC11U24))
00027 #define INFO(x, ...) std::printf("[INF %s %4d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
00028 #define WARN(x, ...) std::printf("[WRN %s %4d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
00029 #define ERR(x, ...)  std::printf("[ERR %s %4d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
00030 static void HexDump(const char * title, const uint8_t * p, int count)
00031 {
00032     int i;
00033     char buf[100] = "0000: ";
00034 
00035     if (*title)
00036         INFO("%s", title);
00037     for (i=0; i<count; ) {
00038         sprintf(buf + strlen(buf), "%02X ", *(p+i));
00039         if ((++i & 0x0F) == 0x00) {
00040             INFO("%s", buf);
00041             if (i < count)
00042                 sprintf(buf, "%04X: ", i);
00043             else
00044                 buf[0] = '\0';
00045         }
00046     }
00047     if (strlen(buf))
00048         INFO("%s", buf);
00049 }
00050 #else
00051 #define INFO(x, ...)
00052 #define WARN(x, ...)
00053 #define ERR(x, ...)
00054 #define HexDump(a, b, c)
00055 #endif
00056 
00057 // Defaults. Users can override this with the init() method.
00058 #define RA8875_DISPLAY_WIDTH  480
00059 #define RA8875_DISPLAY_HEIGHT 272
00060 #define RA8875_COLORDEPTH_BPP 16    /* Not an API */
00061 
00062 #ifdef PERF_METRICS
00063 #define PERFORMANCE_RESET performance.reset()
00064 #define REGISTERPERFORMANCE(a) RegisterPerformance(a)
00065 #define COUNTIDLETIME(a) CountIdleTime(a)
00066 static const char *metricsName[] = {
00067     "Cls", "Pixel", "Pixel Stream", "Boolean Stream",
00068     "Read Pixel", "Read Pixel Stream",
00069     "Line",
00070     "Rectangle", "Rounded Rectangle",
00071     "Triangle", "Circle", "Ellipse"
00072 };
00073 uint16_t commandsUsed[256];  // track which commands are used with simple counter of number of hits.
00074 #else
00075 #define PERFORMANCE_RESET
00076 #define REGISTERPERFORMANCE(a)
00077 #define COUNTIDLETIME(a)
00078 #endif
00079 
00080 // When it is going to poll a register for completion, how many
00081 // uSec should it wait between each polling activity.
00082 #define POLLWAITuSec 10
00083 
00084 // Private RawKeyMap for the Keyboard interface
00085 static const uint8_t DefaultKeyMap[22] = {
00086     0,
00087     1,  2,  3,  4,  5,  6,  7,  8,  9, 10,
00088     11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
00089     255
00090 };
00091 
00092 static const char * ErrMessages[] = {
00093     "noerror",                ///< no errors, command completed successfully
00094     "bad parameter",          ///< one or more parameters are invalid
00095     "file not found",         ///< specified file could not be found
00096     "not bmp format",         ///< file is not a .bmp file
00097     "not ico format",         ///< file is not a .ico file
00098     "not supported format",   ///< file format is not yet supported
00099     "image too big",          ///< image is too large for the screen
00100     "not enough ram",         ///< could not allocate ram for scanline
00101     "touch cal. timeout",     ///< calibration could not complete in time
00102     "external abort",         ///< during an idle callback, the user code initiated an abort
00103 };
00104 
00105 RA8875::RA8875(PinName mosi, PinName miso, PinName sclk, PinName csel, PinName reset, 
00106     const char *name)
00107     : GraphicsDisplay(name)
00108     , spi(mosi, miso, sclk)
00109     , cs(csel)
00110     , res(reset)
00111 {
00112     useTouchPanel = TP_NONE;
00113     m_irq = NULL;
00114     m_i2c = NULL;
00115     c_callback = NULL;
00116     obj_callback = NULL;
00117     method_callback = NULL;
00118     idle_callback = NULL;
00119 }
00120 
00121 
00122 RA8875::RA8875(PinName mosi, PinName miso, PinName sclk, PinName csel, PinName reset, 
00123     PinName sda, PinName scl, PinName irq, const char * name) 
00124     : GraphicsDisplay(name)
00125     , spi(mosi, miso, sclk)
00126     , cs(csel)
00127     , res(reset)
00128 {
00129     useTouchPanel = TP_CAP;
00130     m_irq = new InterruptIn(irq);
00131     m_i2c = new I2C(sda, scl);
00132     c_callback = NULL;
00133     obj_callback = NULL;
00134     method_callback = NULL;
00135     idle_callback = NULL;
00136 
00137     // Cap touch panel config
00138     m_addr = (FT5206_I2C_ADDRESS << 1);
00139     m_i2c->frequency(FT5206_I2C_FREQUENCY);
00140 
00141     // Interrupt
00142     m_irq->mode(PullUp);
00143     m_irq->enable_irq();
00144     m_irq->fall(callback(this, &RA8875::TouchPanelISR));
00145     TouchPanelInit();
00146 }
00147 
00148 
00149 //RA8875::~RA8875()
00150 //{
00151 //}
00152 
00153 RetCode_t RA8875::init(int width, int height, int color_bpp, uint8_t poweron, bool keypadon, bool touchscreenon)
00154 {
00155     font = NULL;                                // no external font, use internal.
00156     pKeyMap = DefaultKeyMap;                    // set default key map
00157     _select(false);                             // deselect the display
00158     frequency(RA8875_DEFAULT_SPI_FREQ);         // data rate
00159     Reset();
00160     // Set PLL based on display size from buy-display.com sample code
00161     if (width == 800) {
00162         WriteCommand(0x88, 0x0C);               // PLLC1 - Phase Lock Loop registers
00163     } else {
00164         WriteCommand(0x88, 0x0B);               // PLLC1 - Phase Lock Loop registers
00165     }
00166     wait_ms(1);
00167     WriteCommand(0x89, 0x02);
00168     wait_ms(1);
00169 
00170     // System Config Register (SYSR)
00171     screenbpp = color_bpp;
00172     if (color_bpp == 16) {
00173         WriteCommand(0x10, 0x0C);               // 16-bpp (65K colors) color depth, 8-bit interface
00174     } else { // color_bpp == 8
00175         WriteCommand(0x10, 0x00);               // 8-bpp (256 colors)
00176     }
00177 
00178     // Set Pixel Clock Setting Register (PCSR) based on display size from buy-display.com sample code
00179     if (width == 800) {
00180         WriteCommand(0x04, 0x81);               // PDAT on PCLK falling edge, PCLK = 4 x System Clock
00181         wait_ms(1);
00182 
00183         // Horizontal Settings
00184         screenwidth = width;
00185         WriteCommand(0x14, width/8 - 1);            //HDWR//Horizontal Display Width Setting Bit[6:0]
00186         WriteCommand(0x15, 0x00);                   //HNDFCR//Horizontal Non-Display Period fine tune Bit[3:0]
00187         WriteCommand(0x16, 0x03);                   //HNDR//Horizontal Non-Display Period Bit[4:0]
00188         WriteCommand(0x17, 0x03);                   //HSTR//HSYNC Start Position[4:0]
00189         WriteCommand(0x18, 0x0B);                   //HPWR//HSYNC Polarity ,The period width of HSYNC.
00190 
00191         // Vertical Settings
00192         screenheight = height;
00193         WriteCommand(0x19, (height-1)&0xFF);        //VDHR0 //Vertical Display Height Bit [7:0]
00194         WriteCommand(0x1a, (height-1)>>8);          //VDHR1 //Vertical Display Height Bit [8]
00195         WriteCommand(0x1b, 0x20);                   //VNDR0 //Vertical Non-Display Period Bit [7:0]
00196         WriteCommand(0x1c, 0x00);                   //VNDR1 //Vertical Non-Display Period Bit [8]
00197         WriteCommand(0x1d, 0x16);                   //VSTR0 //VSYNC Start Position[7:0]
00198         WriteCommand(0x1e, 0x00);                   //VSTR1 //VSYNC Start Position[8]
00199         WriteCommand(0x1f, 0x01);                   //VPWR  //VSYNC Polarity ,VSYNC Pulse Width[6:0]
00200     } else {
00201         WriteCommand(0x04, 0x82);               // PDAT on PCLK falling edge, PCLK = 4 x System Clock
00202         wait_ms(1);
00203 
00204         // Horizontal Settings
00205         screenwidth = width;
00206         WriteCommand(0x14, width/8 - 1);            //HDWR//Horizontal Display Width Setting Bit[6:0]
00207         WriteCommand(0x15, 0x02);                   //HNDFCR//Horizontal Non-Display Period fine tune Bit[3:0]
00208         WriteCommand(0x16, 0x03);                   //HNDR//Horizontal Non-Display Period Bit[4:0]
00209         WriteCommand(0x17, 0x01);                   //HSTR//HSYNC Start Position[4:0]
00210         WriteCommand(0x18, 0x03);                   //HPWR//HSYNC Polarity ,The period width of HSYNC.
00211 
00212         // Vertical Settings
00213         screenheight = height;
00214         WriteCommand(0x19, (height-1)&0xFF);        //VDHR0 //Vertical Display Height Bit [7:0]
00215         WriteCommand(0x1a, (height-1)>>8);          //VDHR1 //Vertical Display Height Bit [8]
00216         WriteCommand(0x1b, 0x0F);                   //VNDR0 //Vertical Non-Display Period Bit [7:0]
00217         WriteCommand(0x1c, 0x00);                   //VNDR1 //Vertical Non-Display Period Bit [8]
00218         WriteCommand(0x1d, 0x0e);                   //VSTR0 //VSYNC Start Position[7:0]
00219         WriteCommand(0x1e, 0x06);                   //VSTR1 //VSYNC Start Position[8]
00220         WriteCommand(0x1f, 0x01);                   //VPWR  //VSYNC Polarity ,VSYNC Pulse Width[6:0]
00221     }
00222 
00223     portraitmode = false;
00224 
00225     if (width >= 800 && height >= 480 && color_bpp > 8) {
00226         WriteCommand(0x20, 0x00);               // DPCR - 1-layer mode when the resolution is too high
00227     } else {
00228         WriteCommand(0x20, 0x80);               // DPCR - 2-layer mode
00229     }
00230 
00231     // Set display image to Blue on Black as default
00232     window(0,0, width, height);             // Initialize to full screen
00233     SetTextCursorControl();
00234     foreground(Blue);
00235     background(Black);
00236     cls(3);
00237 
00238     Power(poweron);
00239     Backlight_u8(poweron);
00240     if (keypadon)
00241         KeypadInit();
00242     if (touchscreenon) {
00243         if (useTouchPanel == TP_NONE)
00244             useTouchPanel = TP_RES;
00245         TouchPanelInit();
00246     }
00247 #ifdef PERF_METRICS
00248     performance.start();
00249     ClearPerformance();
00250 #endif
00251     return noerror;
00252 }
00253 
00254 
00255 RetCode_t RA8875::Reset(void)
00256 {
00257     RetCode_t ret;
00258     
00259     #if 0
00260     if (res != (PinName)NC) {
00261         res = 0;                            // Active low - assert reset
00262         wait_ms(2);                         // must be > 1024 clock periods. (@25 MHz, this is 40.96 usec)
00263         res = 1;                            // de-assert reset
00264     }
00265     #endif
00266     ret = WriteCommand(0x01, 0x01);         // Apply Display Off, Reset
00267     wait_ms(2);                             // no idea if I need to wait, or how long
00268     if (ret == noerror) {
00269         ret = WriteCommand(0x01, 0x00);     // Display off, Remove reset
00270         wait_ms(2);                         // no idea if I need to wait, or how long
00271     }
00272     return ret;
00273 }
00274 
00275 
00276 const char * RA8875::GetErrorMessage(RetCode_t code)
00277 {
00278     if (code >= LastErrCode)
00279         code = bad_parameter;
00280     return ErrMessages[code];
00281 }
00282 
00283 
00284 uint16_t RA8875::GetDrawingLayer(void)
00285 {
00286     return (ReadCommand(0x41) & 0x01);
00287 }
00288 
00289 
00290 RetCode_t RA8875::SelectDrawingLayer(uint16_t layer, uint16_t * prevLayer)
00291 {
00292     unsigned char mwcr1 = ReadCommand(0x41); // retain all but the currently selected layer
00293     
00294     if (prevLayer)
00295         *prevLayer = mwcr1 & 1;
00296     
00297     mwcr1 &= ~0x01; // remove the current layer
00298     if (screenwidth >= 800 && screenheight >= 480 && screenbpp > 8) {
00299         layer = 0;
00300     } else if (layer > 1) {
00301         layer = 0;
00302     }
00303     return WriteCommand(0x41, mwcr1 | layer);
00304 }
00305 
00306 
00307 RA8875::LayerMode_T RA8875::GetLayerMode(void)
00308 {
00309     return (LayerMode_T)(ReadCommand(0x52) & 0x7);
00310 }
00311 
00312 
00313 RetCode_t RA8875::SetLayerMode(LayerMode_T mode)
00314 {
00315     unsigned char ltpr0 = ReadCommand(0x52) & ~0x7; // retain all but the display layer mode
00316     
00317     if (mode <= (LayerMode_T)6) {
00318         WriteCommand(0x52, ltpr0 | (mode & 0x7));
00319         return noerror;
00320     } else {
00321         return bad_parameter;
00322     }
00323 }
00324 
00325 
00326 RetCode_t RA8875::SetLayerTransparency(uint8_t layer1, uint8_t layer2)
00327 {
00328     if (layer1 > 8)
00329         layer1 = 8;
00330     if (layer2 > 8)
00331         layer2 = 8;
00332     WriteCommand(0x53, ((layer2 & 0xF) << 4) | (layer1 & 0xF));
00333     return noerror;
00334 }
00335 
00336 
00337 RetCode_t RA8875::SetBackgroundTransparencyColor(color_t color)
00338 {
00339     return _writeColorTrio(0x67, color);
00340 }
00341 
00342 
00343 color_t RA8875::GetBackgroundTransparencyColor(void)
00344 {
00345     RGBQUAD q;
00346     
00347     q.rgbRed = ReadCommand(0x67);
00348     q.rgbGreen = ReadCommand(0x68);
00349     q.rgbBlue = ReadCommand(0x69);
00350     return RGBQuadToRGB16(&q, 0);
00351 }
00352 
00353 
00354 RetCode_t RA8875::KeypadInit(bool scanEnable, bool longDetect, uint8_t sampleTime, uint8_t scanFrequency,
00355                              uint8_t longTimeAdjustment, bool interruptEnable, bool wakeupEnable)
00356 {
00357     uint8_t value = 0;
00358 
00359     if (sampleTime > 3 || scanFrequency > 7 || longTimeAdjustment  > 3)
00360         return bad_parameter;
00361     value |= (scanEnable) ? 0x80 : 0x00;
00362     value |= (longDetect) ? 0x40 : 0x00;
00363     value |= (sampleTime & 0x03) << 4;
00364     value |= (scanFrequency & 0x07);
00365     WriteCommand(0xC0, value);   // KSCR1 - Enable Key Scan (and ignore possibility of an error)
00366 
00367     value = 0;
00368     value |= (wakeupEnable) ? 0x80 : 0x00;
00369     value |= (longTimeAdjustment & 0x03) << 2;
00370     WriteCommand(0xC1, value);  // KSCR2 - (and ignore possibility of an error)
00371 
00372     value = ReadCommand(0xF0);          // (and ignore possibility of an error)
00373     value &= ~0x10;
00374     value |= (interruptEnable) ? 0x10 : 0x00;
00375     return WriteCommand(0xF0, value);   // INT
00376 }
00377 
00378 
00379 RetCode_t RA8875::SetKeyMap(const uint8_t * CodeList)
00380 {
00381     pKeyMap = CodeList;
00382     return noerror;
00383 }
00384 
00385 
00386 bool RA8875::readable(void)
00387 {
00388     return (ReadCommand(0xF1) & 0x10);  // check KS status - true if kbhit
00389 }
00390 
00391 
00392 uint8_t RA8875::getc(void)
00393 {
00394     //#define GETC_DEV      // for development
00395 #ifdef GETC_DEV
00396     uint8_t keyCode1, keyCode2;
00397 #endif
00398     uint8_t keyCode3;
00399     static uint8_t count = 0;
00400     uint8_t col, row;
00401     uint8_t key;
00402     
00403     while (!readable()) {
00404         wait_us(POLLWAITuSec);
00405         // COUNTIDLETIME(POLLWAITuSec);     // As it is voluntary to call the getc and pend. Don't tally it.
00406         if (idle_callback) {
00407             if (external_abort == (*idle_callback)(getc_wait, 0)) {
00408                 return 0;
00409             }
00410         }
00411     }
00412     // read the key press number
00413     uint8_t keyNumReg = ReadCommand(0xC1) & 0x03;
00414     count++;
00415     switch (keyNumReg) {
00416         case 0x01:      // one key
00417             keyCode3 = ReadCommand(0xC2);
00418 #ifdef GETC_DEV
00419             keyCode2 = 0;
00420             keyCode1 = 0;
00421 #endif
00422             break;
00423         case 0x02:      // two keys
00424             keyCode3 = ReadCommand(0xC3);
00425 #ifdef GETC_DEV
00426             keyCode2 = ReadCommand(0xC2);
00427             keyCode1 = 0;
00428 #endif
00429             break;
00430         case 0x03:      // three keys
00431             keyCode3 = ReadCommand(0xC4);
00432 #ifdef GETC_DEV
00433             keyCode2 = ReadCommand(0xC3);
00434             keyCode1 = ReadCommand(0xC2);
00435 #endif
00436             break;
00437         default:         // no keys (key released)
00438             keyCode3 = 0xFF;
00439 #ifdef GETC_DEV
00440             keyCode2 = 0;
00441             keyCode1 = 0;
00442 #endif
00443             break;
00444     }
00445     if (keyCode3 == 0xFF)
00446         key = pKeyMap[0];                    // Key value 0
00447     else {
00448         row = (keyCode3 >> 4) & 0x03;
00449         col = (keyCode3 &  7);
00450         key = row * 5 + col + 1;    // Keys value 1 - 20
00451         if (key > 21) {
00452             key = 21;
00453         }
00454         key = pKeyMap[key];
00455         key |= (keyCode3 & 0x80);   // combine the key held flag
00456     }
00457 #if GETC_DEV // for Development only
00458     SetTextCursor(0, 20);
00459     printf("   Reg: %02x\r\n", keyNumReg);
00460     printf("  key1: %02x\r\n", keyCode1);
00461     printf("  key2: %02x\r\n", keyCode2);
00462     printf("  key3: %02x\r\n", keyCode3);
00463     printf(" count: %02X\r\n", count);
00464     printf("   key: %02X\r\n", key);
00465 #endif
00466     WriteCommand(0xF1, 0x10);       // Clear KS status
00467     return key;
00468 }
00469 
00470 
00471 #ifdef PERF_METRICS
00472 void RA8875::ClearPerformance()
00473 {
00474     int i;
00475     
00476     for (i=0; i<METRICCOUNT; i++)
00477         metrics[i] = 0;
00478     idletime_usec = 0;
00479     for (i=0; i<256; i++)
00480         commandsUsed[i] = 0;
00481 }
00482 
00483 
00484 void RA8875::RegisterPerformance(method_e method)
00485 {
00486     unsigned long elapsed = performance.read_us();
00487 
00488     if (method < METRICCOUNT && elapsed > metrics[method])
00489         metrics[method] = elapsed;
00490 }
00491 
00492 
00493 void RA8875::CountIdleTime(uint32_t t)
00494 {
00495     idletime_usec += t;
00496 }
00497 
00498 
00499 void RA8875::ReportPerformance(Serial & pc)
00500 {
00501     int i;
00502     
00503     pc.printf("\r\nPerformance Metrics\r\n");
00504     for (i=0; i<METRICCOUNT; i++) {
00505         pc.printf("%10d uS %s\r\n", metrics[i], metricsName[i]);
00506     }
00507     pc.printf("%10d uS Idle time polling display for ready.\r\n", idletime_usec);
00508     for (i=0; i<256; i++) {
00509         if (commandsUsed[i])
00510             pc.printf("Command %02X used %5d times.\r\n", i, commandsUsed[i]);
00511     }
00512 }
00513 #endif
00514 
00515 
00516 bool RA8875::Intersect(rect_t rect, point_t p)
00517 {
00518     if (p.x >= min(rect.p1.x, rect.p2.x) && p.x <= max(rect.p1.x, rect.p2.x)
00519     && p.y >= min(rect.p1.y, rect.p2.y) && p.y <= max(rect.p1.y, rect.p2.y))
00520         return true;
00521     else
00522         return false;
00523 }
00524 
00525 
00526 bool RA8875::Intersect(rect_t rect1, rect_t rect2)
00527 {
00528 #if 1
00529     // If one rectangle is on left side of other
00530     if (max(rect1.p1.x,rect1.p2.x) < min(rect2.p1.x,rect2.p2.x)
00531         || min(rect1.p1.x, rect1.p2.x) > max(rect2.p1.x, rect2.p2.x))
00532         return false;
00533     // If one rectangle is above other
00534     if (max(rect1.p1.y, rect1.p2.y) < min(rect2.p1.y, rect2.p2.y)
00535         || min(rect1.p1.y, rect1.p2.y) > max(rect2.p1.y, rect2.p2.y))
00536         return false;
00537     return true;            // all that's left is they overlap
00538 #else
00539     point_t bl, tr;
00540     bl.x = rect2.p1.x;
00541     bl.y = rect2.p2.y;
00542     tr.x = rect2.p2.x;
00543     tr.y = rect2.p1.y;
00544     if (Intersect(rect1, rect2.p1) || Intersect(rect1, rect2.p2)
00545         || Intersect(rect1, bl) || Intersect(rect1, tr))
00546         return true;
00547     else
00548         return false;
00549 #endif
00550 }
00551 
00552 
00553 bool RA8875::Intersect(rect_t * pRect1, const rect_t * pRect2)
00554 {
00555     if (Intersect(*pRect1, *pRect2)) {
00556         rect_t iSect;
00557         
00558         iSect.p1.x = max(min(pRect1->p1.x,pRect1->p2.x),min(pRect2->p1.x,pRect2->p2.x));
00559         iSect.p1.y = max(min(pRect1->p1.y,pRect1->p2.y),min(pRect2->p1.y,pRect2->p2.y));
00560         iSect.p2.x = min(max(pRect1->p1.x,pRect1->p2.x),max(pRect2->p1.x,pRect2->p2.x));
00561         iSect.p2.y = min(max(pRect1->p1.y,pRect1->p2.y),max(pRect2->p1.y,pRect2->p2.y));
00562         *pRect1 = iSect;
00563         return true;
00564     } else {
00565         return false;
00566     }
00567 }
00568 
00569 
00570 RetCode_t RA8875::WriteCommandW(uint8_t command, uint16_t data)
00571 {
00572     WriteCommand(command, data & 0xFF);
00573     WriteCommand(command+1, data >> 8);
00574     return noerror;
00575 }
00576 
00577 
00578 RetCode_t RA8875::WriteCommand(unsigned char command, unsigned int data)
00579 {
00580 #ifdef PERF_METRICS
00581     if (commandsUsed[command] < 65535)
00582         commandsUsed[command]++;
00583 #endif
00584     _select(true);
00585     _spiwrite(0x80);            // RS:1 (Cmd/Status), RW:0 (Write)
00586     _spiwrite(command);
00587     if (data <= 0xFF) {   // only if in the valid range
00588         _spiwrite(0x00);
00589         _spiwrite(data);
00590     }
00591     _select(false);
00592     return noerror;
00593 }
00594 
00595 
00596 RetCode_t RA8875::WriteDataW(uint16_t data)
00597 {
00598     _select(true);
00599     _spiwrite(0x00);            // RS:0 (Data), RW:0 (Write)
00600     _spiwrite(data & 0xFF);
00601     _spiwrite(data >> 8);
00602     _select(false);
00603     return noerror;
00604 }
00605 
00606 
00607 RetCode_t RA8875::WriteData(unsigned char data)
00608 {
00609     _select(true);
00610     _spiwrite(0x00);            // RS:0 (Data), RW:0 (Write)
00611     _spiwrite(data);
00612     _select(false);
00613     return noerror;
00614 }
00615 
00616 
00617 unsigned char RA8875::ReadCommand(unsigned char command)
00618 {
00619     WriteCommand(command);
00620     return ReadData();
00621 }
00622 
00623 uint16_t RA8875::ReadCommandW(unsigned char command)
00624 {
00625     WriteCommand(command);
00626     return ReadDataW();
00627 }
00628 
00629 unsigned char RA8875::ReadData(void)
00630 {
00631     unsigned char data;
00632 
00633     _select(true);
00634     _spiwrite(0x40);            // RS:0 (Data), RW:1 (Read)
00635     data = _spiread();
00636     _select(false);
00637     return data;
00638 }
00639 
00640 
00641 uint16_t RA8875::ReadDataW(void)
00642 {
00643     uint16_t data;
00644 
00645     _select(true);
00646     _spiwrite(0x40);            // RS:0 (Data), RW:1 (Read)
00647     data  = _spiread();
00648     data |= (_spiread() << 8);
00649     _select(false);
00650     return data;
00651 }
00652 
00653 
00654 unsigned char RA8875::ReadStatus(void)
00655 {
00656     unsigned char data;
00657 
00658     _select(true);
00659     _spiwrite(0xC0);            // RS:1 (Cmd/Status), RW:1 (Read) (Read STSR)
00660     data = _spiread();
00661     _select(false);
00662     return data;
00663 }
00664 
00665 
00666 /// @todo add a timeout and return false, but how long
00667 /// to wait since some operations can be very long.
00668 bool RA8875::_WaitWhileBusy(uint8_t mask)
00669 {
00670     int i = 20000/POLLWAITuSec; // 20 msec max
00671 
00672     while (i-- && ReadStatus() & mask) {
00673         wait_us(POLLWAITuSec);
00674         COUNTIDLETIME(POLLWAITuSec);
00675         if (idle_callback) {
00676             if (external_abort == (*idle_callback)(status_wait, 0)) {
00677                 return false;
00678             }
00679         }
00680     }
00681     if (i)
00682         return true;
00683     else
00684         return false;
00685 }
00686 
00687 
00688 /// @todo add a timeout and return false, but how long
00689 /// to wait since some operations can be very long.
00690 bool RA8875::_WaitWhileReg(uint8_t reg, uint8_t mask)
00691 {
00692     int i = 20000/POLLWAITuSec; // 20 msec max
00693 
00694     while (i-- && ReadCommand(reg) & mask) {
00695         wait_us(POLLWAITuSec);
00696         COUNTIDLETIME(POLLWAITuSec);
00697         if (idle_callback) {
00698             if (external_abort == (*idle_callback)(command_wait, 0)) {
00699                 return false;
00700             }
00701         }
00702     }
00703     if (i)
00704         return true;
00705     else
00706         return false;
00707 }
00708 
00709 // RRRR RGGG GGGB BBBB
00710 // 4321 0543 2104 3210
00711 //           RRRG GGBB
00712 //           2102 1010
00713 uint8_t RA8875::_cvt16to8(color_t c16)
00714 {
00715     return ((c16 >> 8) & 0xE0)
00716         | ((c16 >> 6) & 0x1C)
00717         | ((c16 >> 3) & 0x03);
00718 }
00719 
00720 //           RRRG GGBB
00721 //           2102 1010
00722 // RRRR RGGG GGGB BBBB
00723 // 2101 0543 2104 3210
00724 color_t RA8875::_cvt8to16(uint8_t c8)
00725 {
00726     color_t c16;
00727     color_t temp = (color_t)c8;
00728     
00729     c16 = ((temp & 0xE0) << 8)
00730         | ((temp & 0xC0) << 5)
00731         | ((temp & 0x1C) << 6)
00732         | ((temp & 0x1C) << 3)
00733         | ((temp & 0x03) << 3)
00734         | ((temp & 0x03) << 1)
00735         | ((temp & 0x03) >> 1);
00736     c16 = (c16 << 8) | (c16 >> 8);
00737     return c16;
00738 }
00739 
00740 RetCode_t RA8875::_writeColorTrio(uint8_t regAddr, color_t color)
00741 {
00742     RetCode_t rt = noerror;
00743     
00744     if (screenbpp == 16) {
00745         WriteCommand(regAddr+0, (color>>11));                  // BGCR0
00746         WriteCommand(regAddr+1, (unsigned char)(color>>5));    // BGCR1
00747         rt = WriteCommand(regAddr+2, (unsigned char)(color));       // BGCR2
00748     } else {
00749         uint8_t r, g, b;
00750         
00751         // RRRR RGGG GGGB BBBB      RGB
00752         // RRR   GGG    B B
00753         r = (uint8_t)((color) >> 13);
00754         g = (uint8_t)((color) >> 8);
00755         b = (uint8_t)((color) >> 3);
00756         WriteCommand(regAddr+0, r);  // BGCR0
00757         WriteCommand(regAddr+1, g);  // BGCR1
00758         rt = WriteCommand(regAddr+2, b);  // BGCR2
00759     }
00760     return rt;
00761 }
00762 
00763 color_t RA8875::_readColorTrio(uint8_t regAddr)
00764 {
00765     color_t color;
00766     uint8_t r, g, b;
00767     
00768     r = ReadCommand(regAddr+0);
00769     g = ReadCommand(regAddr+1);
00770     b = ReadCommand(regAddr+2);
00771     if (screenbpp == 16) {
00772         // 000R RRRR 00GG GGGG 000B BBBB
00773         // RRRR RGGG GGGB BBBB
00774         color  = (r & 0x1F) << 11;
00775         color |= (g & 0x3F) << 5;
00776         color |= (b & 0x1F);
00777     } else {
00778         // RRRG GGBB
00779         // RRRR RGGG GGGB BBBB
00780         color  = (r & 0x07) << 13;
00781         color |= (g & 0x07) << 8;
00782         color |= (b & 0x03) << 3;
00783     }
00784     return color;
00785 }
00786 
00787 
00788 dim_t RA8875::fontwidth(void)
00789 {
00790     if (font == NULL)
00791         return (((ReadCommand(0x22) >> 2) & 0x3) + 1) * 8;
00792     else
00793         return extFontWidth;
00794 }
00795 
00796 
00797 dim_t RA8875::fontheight(void)
00798 {
00799     if (font == NULL)
00800         return (((ReadCommand(0x22) >> 0) & 0x3) + 1) * 16;
00801     else
00802         return extFontHeight;
00803 }
00804 
00805 
00806 RetCode_t RA8875::locate(textloc_t column, textloc_t row)
00807 {
00808     return SetTextCursor(column * fontwidth(), row * fontheight());
00809 }
00810 
00811 
00812 int RA8875::columns(void)
00813 {
00814     return screenwidth / fontwidth();
00815 }
00816 
00817 
00818 int RA8875::rows(void)
00819 {
00820     return screenheight / fontheight();
00821 }
00822 
00823 
00824 dim_t RA8875::width(void)
00825 {
00826     if (portraitmode)
00827         return screenheight;
00828     else
00829         return screenwidth;
00830 }
00831 
00832 
00833 dim_t RA8875::height(void)
00834 {
00835     if (portraitmode)
00836         return screenwidth;
00837     else
00838         return screenheight;
00839 }
00840 
00841 
00842 dim_t RA8875::color_bpp(void)
00843 {
00844     return screenbpp;
00845 }
00846 
00847 RetCode_t RA8875::SetTextCursor(point_t p)
00848 {
00849     return SetTextCursor(p.x, p.y);
00850 }
00851 
00852 RetCode_t RA8875::SetTextCursor(loc_t x, loc_t y)
00853 {
00854     INFO("SetTextCursor(%d, %d)", x, y);
00855     cursor_x = x;     // set these values for non-internal fonts
00856     cursor_y = y;
00857     WriteCommandW(0x2A, x);
00858     WriteCommandW(0x2C, y);
00859     return noerror;
00860 }
00861 
00862 point_t RA8875::GetTextCursor(void)
00863 {
00864     point_t p;
00865     
00866     p.x = GetTextCursor_X();
00867     p.y = GetTextCursor_Y();
00868     return p;
00869 }
00870 
00871 loc_t RA8875::GetTextCursor_Y(void)
00872 {
00873     loc_t y;
00874     
00875     if (font == NULL)
00876         y = ReadCommand(0x2C) | (ReadCommand(0x2D) << 8);
00877     else
00878         y = cursor_y;
00879     INFO("GetTextCursor_Y = %d", y);
00880     return y;
00881 }
00882 
00883 
00884 loc_t RA8875::GetTextCursor_X(void)
00885 {
00886     loc_t x;
00887     
00888     if (font == NULL)
00889         x = ReadCommand(0x2A) | (ReadCommand(0x2B) << 8);
00890     else
00891         x = cursor_x;
00892     INFO("GetTextCursor_X = %d", x);
00893     return x;
00894 }
00895 
00896 
00897 RetCode_t RA8875::SetTextCursorControl(cursor_t cursor, bool blink)
00898 {
00899     unsigned char mwcr0 = ReadCommand(0x40) & 0x0F; // retain direction, auto-increase
00900     unsigned char mwcr1 = ReadCommand(0x41) & 0x01; // retain currently selected layer
00901     unsigned char horz = 0;
00902     unsigned char vert = 0;
00903 
00904     mwcr0 |= 0x80;                  // text mode
00905     if (cursor != NOCURSOR)
00906         mwcr0 |= 0x40;              // visible
00907     if (blink)
00908         mwcr0 |= 0x20;              // blink
00909     WriteCommand(0x40, mwcr0);      // configure the cursor
00910     WriteCommand(0x41, mwcr1);      // close the graphics cursor
00911     WriteCommand(0x44, 0x1f);       // The cursor flashing cycle
00912     switch (cursor) {
00913         case IBEAM:
00914             horz = 0x01;
00915             vert = 0x1F;
00916             break;
00917         case UNDER:
00918             horz = 0x07;
00919             vert = 0x01;
00920             break;
00921         case BLOCK:
00922             horz = 0x07;
00923             vert = 0x1F;
00924             break;
00925         case NOCURSOR:
00926         default:
00927             break;
00928     }
00929     WriteCommand(0x4e, horz);       // The cursor size horz
00930     WriteCommand(0x4f, vert);       // The cursor size vert
00931     return noerror;
00932 }
00933 
00934 
00935 RetCode_t RA8875::SetTextFont(RA8875::font_t font)
00936 {
00937     if (/*font >= RA8875::ISO8859_1 && */ font <= RA8875::ISO8859_4) {
00938         WriteCommand(0x21, (unsigned int)(font));
00939         return noerror;
00940     } else {
00941         return bad_parameter;
00942     }
00943 }
00944 
00945 
00946 RetCode_t RA8875::SetOrientation(RA8875::orientation_t angle)
00947 {
00948     uint8_t fncr1Val = ReadCommand(0x22);
00949     uint8_t dpcrVal = ReadCommand(0x20);
00950     
00951     fncr1Val &= ~0x10;      // remove the old direction bit
00952     dpcrVal &= ~0x0C;       // remove the old scan direction bits
00953     switch (angle) {
00954         case RA8875::normal:
00955             //fncr1Val |= 0x10;
00956             //dpcrVal |= 0x00;
00957             portraitmode = false;
00958             break;
00959         case RA8875::rotate_90:
00960             fncr1Val |= 0x10;
00961             dpcrVal |= 0x08;
00962             portraitmode = true;
00963             break;
00964         case RA8875::rotate_180:
00965             //fncr1Val |= 0x00;
00966             dpcrVal |= 0x0C;
00967             portraitmode = false;
00968             break;
00969         case RA8875::rotate_270:
00970             fncr1Val |= 0x10;
00971             dpcrVal |= 0x04;
00972             portraitmode = true;
00973             break;
00974         default:
00975             return bad_parameter;
00976     }
00977     INFO("Orientation: %d, %d", angle, portraitmode);
00978     WriteCommand(0x22, fncr1Val);
00979     return WriteCommand(0x20, dpcrVal);
00980 }
00981 
00982 
00983 RetCode_t RA8875::SetTextFontControl(fill_t fillit,
00984                                      RA8875::HorizontalScale hScale,
00985                                      RA8875::VerticalScale vScale,
00986                                      RA8875::alignment_t alignment)
00987 {
00988     if (hScale >= 1 && hScale <= 4 &&
00989             vScale >= 1 && vScale <= 4) {
00990         uint8_t fncr1Val = ReadCommand(0x22);
00991         
00992         fncr1Val &= ~0x10;      // do not disturb the rotate flag
00993         if (alignment == align_full)
00994             fncr1Val |= 0x80;
00995         if (fillit == NOFILL)
00996             fncr1Val |= 0x40;
00997         fncr1Val |= ((hScale - 1) << 2);
00998         fncr1Val |= ((vScale - 1) << 0);
00999         return WriteCommand(0x22, fncr1Val);
01000     } else {
01001         return bad_parameter;
01002     }
01003 }
01004 
01005 
01006 RetCode_t RA8875::SetTextFontSize(RA8875::HorizontalScale hScale, RA8875::VerticalScale vScale)
01007 {
01008     unsigned char reg = ReadCommand(0x22);
01009 
01010     if (vScale == -1)
01011         vScale = hScale;
01012     if (hScale >= 1 && hScale <= 4 && vScale >= 1 && vScale <= 4) {
01013         reg &= 0xF0;    // keep the high nibble as is.
01014         reg |= ((hScale - 1) << 2);
01015         reg |= ((vScale - 1) << 0);
01016         WriteCommand(0x22, reg);
01017         return noerror;
01018     } else {
01019         return bad_parameter;
01020     }
01021 }
01022 
01023 RetCode_t RA8875::GetTextFontSize(RA8875::HorizontalScale * hScale, RA8875::VerticalScale * vScale)
01024 {
01025     unsigned char reg = ReadCommand(0x22);
01026 
01027     if (hScale)
01028         *hScale = 1 + (reg >> 2) & 0x03;
01029     if (vScale)
01030         *vScale = 1 + reg & 0x03;
01031     return noerror;
01032 }
01033 
01034 int RA8875::_putc(int c)
01035 {
01036     if (font == NULL) {
01037         return _internal_putc(c);
01038     } else {
01039         return _external_putc(c);
01040     }
01041 }
01042 
01043 
01044 
01045 // Questions to ponder -
01046 // - if we choose to wrap to the next line, because the character won't fit on the current line,
01047 //      should it erase the space to the width of the screen (in case there is leftover junk there)?
01048 // - it currently wraps from the bottom of the screen back to the top. I have pondered what
01049 //      it might take to scroll the screen - but haven't thought hard enough about it.
01050 //
01051 int RA8875::_external_putc(int c)
01052 {
01053     if (c) {
01054         if (c == '\r') {
01055             cursor_x = windowrect.p1.x;
01056         } else if (c == '\n') {
01057             cursor_y += extFontHeight;
01058         } else {
01059             dim_t charWidth, charHeight;
01060             const uint8_t * charRecord;
01061             
01062             charRecord = getCharMetrics(c, &charWidth, &charHeight);
01063             //int advance = charwidth(c);
01064             INFO("(%d,%d) - (%d,%d):(%d,%d), charWidth: %d '%c", cursor_x, cursor_y, 
01065                 windowrect.p1.x, windowrect.p1.y, windowrect.p2.x, windowrect.p2.y,
01066                 charWidth, c);
01067             if (charRecord) {
01068                 //cursor_x += advance;
01069                 if (cursor_x + charWidth >= windowrect.p2.x) {
01070                     cursor_x = windowrect.p1.x;
01071                     cursor_y += charHeight;
01072                 }
01073                 if (cursor_y + charHeight >= windowrect.p2.y) {
01074                     cursor_y = windowrect.p1.y;               // @todo Should it scroll?
01075                 }
01076                 (void)character(cursor_x, cursor_y, c);
01077                 cursor_x += charWidth;
01078             }
01079         }
01080     }
01081     return c;
01082 }
01083 
01084 
01085 int RA8875::_internal_putc(int c)
01086 {
01087     if (c) {
01088         unsigned char mwcr0;
01089 
01090         mwcr0 = ReadCommand(0x40);
01091         if ((mwcr0 & 0x80) == 0x00) {
01092             WriteCommand(0x40, 0x80 | mwcr0);    // Put in Text mode if not already
01093         }
01094         if (c == '\r') {
01095             loc_t x;
01096             x = ReadCommand(0x30) | (ReadCommand(0x31) << 8);   // Left edge of active window
01097             WriteCommandW(0x2A, x);
01098         } else if (c == '\n') {
01099             loc_t y;
01100             y = ReadCommand(0x2C) | (ReadCommand(0x2D) << 8);   // current y location
01101             y += fontheight();
01102             if (y >= height())               // @TODO after bottom of active window, then scroll window?
01103                 y = 0;
01104             WriteCommandW(0x2C, y);
01105         } else {
01106             WriteCommand(0x02);                 // RA8875 Internal Fonts
01107             _select(true);
01108             WriteData(c);
01109             _WaitWhileBusy(0x80);
01110             _select(false);
01111         }
01112     }
01113     return c;
01114 }
01115 
01116 
01117 RetCode_t RA8875::_StartGraphicsStream(void)
01118 {
01119     WriteCommand(0x40,0x00);    // Graphics write mode
01120     WriteCommand(0x02);         // Prepare for streaming data
01121     return noerror;
01122 }
01123 
01124 
01125 RetCode_t RA8875::_EndGraphicsStream(void)
01126 {
01127     return noerror;
01128 }
01129 
01130 
01131 RetCode_t RA8875::_putp(color_t pixel)
01132 {
01133     WriteDataW((pixel>>8) | (pixel<<8));
01134     return noerror;
01135 }
01136 
01137 
01138 void RA8875::puts(loc_t x, loc_t y, const char * string)
01139 {
01140     SetTextCursor(x,y);
01141     puts(string);
01142 }
01143 
01144 
01145 void RA8875::puts(const char * string)
01146 {
01147     if (font == NULL) {
01148         WriteCommand(0x40,0x80);    // Put in Text mode if internal font
01149     }
01150     if (*string != '\0') {
01151         while (*string) {           // @TODO calling individual _putc is slower... optimizations?
01152             _putc(*string++);
01153         }
01154     }
01155 }
01156 
01157 
01158 RetCode_t RA8875::SetGraphicsCursor(loc_t x, loc_t y)
01159 {
01160     WriteCommandW(0x46, x);
01161     WriteCommandW(0x48, y);
01162     return noerror;
01163 }
01164 
01165 RetCode_t RA8875::SetGraphicsCursor(point_t p)
01166 {
01167     return SetGraphicsCursor(p.x, p.y);
01168 }
01169 
01170 point_t RA8875::GetGraphicsCursor(void)
01171 {
01172     point_t p;
01173     
01174     p.x = ReadCommandW(0x46);
01175     p.y = ReadCommandW(0x48);
01176     return p;
01177 }
01178 
01179 RetCode_t RA8875::SetGraphicsCursorRead(loc_t x, loc_t y)
01180 {
01181     WriteCommandW(0x4A, x);
01182     WriteCommandW(0x4C, y);
01183     return noerror;
01184 }
01185 
01186 RetCode_t RA8875::window(rect_t r)
01187 {
01188     return window(r.p1.x, r.p1.y, r.p2.x + 1 - r.p1.x, r.p2.y + 1 - r.p1.y);
01189 }
01190 
01191 RetCode_t RA8875::window(loc_t x, loc_t y, dim_t width, dim_t height)
01192 {
01193     INFO("window(%d,%d,%d,%d)", x, y, width, height);
01194     if (width == (dim_t)-1)
01195         width = screenwidth - x;
01196     if (height == (dim_t)-1)
01197         height = screenheight - y;
01198     windowrect.p1.x = x;
01199     windowrect.p1.y = y;
01200     windowrect.p2.x = x + width - 1;
01201     windowrect.p2.y = y + height - 1;
01202     GraphicsDisplay::window(x,y, width,height);
01203     WriteCommandW(0x30, x);
01204     WriteCommandW(0x32, y);
01205     WriteCommandW(0x34, (x+width-1));
01206     WriteCommandW(0x36, (y+height-1));
01207     //SetTextCursor(x,y);
01208     //SetGraphicsCursor(x,y);
01209     return noerror;
01210 }
01211 
01212 
01213 RetCode_t RA8875::cls(uint16_t layers)
01214 {
01215     RetCode_t ret;
01216 
01217     PERFORMANCE_RESET;
01218     if (layers == 0) {
01219         ret = clsw(FULLWINDOW);
01220     } else if (layers > 3) {
01221         ret = bad_parameter;
01222     } else {
01223         uint16_t prevLayer = GetDrawingLayer();
01224         if (layers & 1) {
01225             SelectDrawingLayer(0);
01226             clsw(FULLWINDOW);
01227         }
01228         if (layers & 2) {
01229             SelectDrawingLayer(1);
01230             clsw(FULLWINDOW);
01231         }
01232         SelectDrawingLayer(prevLayer);
01233     }
01234     ret = SetTextCursor(0,0);
01235     ret = locate(0,0);
01236     REGISTERPERFORMANCE(PRF_CLS);
01237     return ret;
01238 }
01239 
01240 
01241 RetCode_t RA8875::clsw(RA8875::Region_t region)
01242 {
01243     PERFORMANCE_RESET;
01244     WriteCommand(0x8E, (region == ACTIVEWINDOW) ? 0xC0 : 0x80);
01245     if (!_WaitWhileReg(0x8E, 0x80)) {
01246         REGISTERPERFORMANCE(PRF_CLS);
01247         return external_abort;
01248     }
01249     REGISTERPERFORMANCE(PRF_CLS);
01250     return noerror;
01251 }
01252 
01253 
01254 RetCode_t RA8875::pixel(point_t p, color_t color)
01255 {
01256     return pixel(p.x, p.y, color);
01257 }
01258 
01259 RetCode_t RA8875::pixel(point_t p)
01260 {
01261     return pixel(p.x, p.y);
01262 }
01263 
01264 RetCode_t RA8875::pixel(loc_t x, loc_t y, color_t color)
01265 {
01266     RetCode_t ret;
01267 
01268     PERFORMANCE_RESET;
01269     ret = pixelStream(&color, 1, x,y);
01270     REGISTERPERFORMANCE(PRF_DRAWPIXEL);
01271     return ret;
01272 }
01273 
01274 
01275 RetCode_t RA8875::pixel(loc_t x, loc_t y)
01276 {
01277     RetCode_t ret;
01278 
01279     PERFORMANCE_RESET;
01280     color_t color = GetForeColor();
01281     ret = pixelStream(&color, 1, x, y);
01282     REGISTERPERFORMANCE(PRF_DRAWPIXEL);
01283     return ret;
01284 }
01285 
01286 
01287 RetCode_t RA8875::pixelStream(color_t * p, uint32_t count, loc_t x, loc_t y)
01288 {
01289     PERFORMANCE_RESET;
01290     SetGraphicsCursor(x, y);
01291     _StartGraphicsStream();
01292     _select(true);
01293     _spiwrite(0x00);         // Cmd: write data
01294     while (count--) {
01295         if (screenbpp == 16) {
01296             _spiwrite(*p >> 8);
01297             _spiwrite(*p & 0xFF);
01298         } else {
01299             _spiwrite(_cvt16to8(*p));
01300         }
01301         p++;
01302     }
01303     _select(false);
01304     _EndGraphicsStream();
01305     REGISTERPERFORMANCE(PRF_PIXELSTREAM);
01306     return(noerror);
01307 }
01308 
01309 RetCode_t RA8875::booleanStream(loc_t x, loc_t y, dim_t w, dim_t h, const uint8_t * boolStream) 
01310 {
01311     PERFORMANCE_RESET;
01312     rect_t restore = windowrect;
01313     
01314     window(x, y, w, h);
01315     SetGraphicsCursor(x, y);
01316     _StartGraphicsStream();
01317     _select(true);
01318     
01319     _setWriteSpeed(true);
01320     
01321     spi.write(0x00);         // Cmd: write data
01322     while (h--) {
01323         uint8_t pixels = w;
01324         uint8_t bitmask = 0x01;
01325         
01326         while (pixels) {
01327             uint8_t byte = *boolStream;
01328             //INFO("byte, mask: %02X, %02X", byte, bitmask);
01329             color_t c = (byte & bitmask) ? _foreground : _background;
01330                 if (screenbpp == 16) {
01331                     spi.fastWrite(c >> 8);
01332                     spi.fastWrite(c & 0xFF);
01333                 } else {
01334                     spi.fastWrite(_cvt16to8(c));
01335                 }
01336             bitmask <<= 1;
01337             if (pixels > 1 && bitmask == 0) {
01338                 bitmask = 0x01;
01339                 boolStream++;
01340             }
01341             pixels--;
01342         }
01343         boolStream++;
01344     }
01345     spi.clearRX();
01346     _select(false);
01347     _EndGraphicsStream();
01348     window(restore);
01349     REGISTERPERFORMANCE(PRF_BOOLSTREAM);
01350     return(noerror);
01351 }
01352 
01353 color_t RA8875::getPixel(loc_t x, loc_t y)
01354 {
01355     color_t pixel;
01356 
01357     PERFORMANCE_RESET;
01358     WriteCommand(0x40,0x00);    // Graphics write mode
01359     SetGraphicsCursorRead(x, y);
01360     WriteCommand(0x02);
01361     _select(true);
01362     _spiwrite(0x40);         // Cmd: read data
01363     _spiwrite(0x00);         // dummy read
01364     if (screenbpp == 16) {
01365         pixel  = _spiread();
01366         pixel |= (_spiread() << 8);
01367     } else {
01368         pixel = _cvt8to16(_spiread());
01369     }
01370     _select(false);
01371     REGISTERPERFORMANCE(PRF_READPIXEL);
01372     return pixel;
01373 }
01374 
01375 
01376 RetCode_t RA8875::getPixelStream(color_t * p, uint32_t count, loc_t x, loc_t y)
01377 {
01378     color_t pixel;
01379     RetCode_t ret = noerror;
01380 
01381     PERFORMANCE_RESET;
01382     ret = WriteCommand(0x40,0x00);    // Graphics write mode
01383     ret = SetGraphicsCursorRead(x, y);
01384     ret = WriteCommand(0x02);
01385     _select(true);
01386     _spiwrite(0x40);         // Cmd: read data
01387     _spiwrite(0x00);         // dummy read
01388     if (screenbpp == 16)
01389         _spiwrite(0x00);     // dummy read is only necessary when in 16-bit mode
01390     while (count--) {
01391         if (screenbpp == 16) {
01392             pixel  = _spiread();
01393             pixel |= (_spiread() << 8);
01394         } else {
01395             pixel = _cvt8to16(_spiread());
01396         }
01397         *p++ = pixel;
01398     }
01399     _select(false);
01400     REGISTERPERFORMANCE(PRF_READPIXELSTREAM);
01401     return ret;
01402 }
01403 
01404 
01405 RetCode_t RA8875::line(point_t p1, point_t p2)
01406 {
01407     return line(p1.x, p1.y, p2.x, p2.y);
01408 }
01409 
01410 
01411 RetCode_t RA8875::line(point_t p1, point_t p2, color_t color)
01412 {
01413     return line(p1.x, p1.y, p2.x, p2.y, color);
01414 }
01415 
01416 
01417 RetCode_t RA8875::line(loc_t x1, loc_t y1, loc_t x2, loc_t y2, color_t color)
01418 {
01419     foreground(color);
01420     return line(x1,y1,x2,y2);
01421 }
01422 
01423 
01424 RetCode_t RA8875::line(loc_t x1, loc_t y1, loc_t x2, loc_t y2)
01425 {
01426     PERFORMANCE_RESET;
01427     if (x1 == x2 && y1 == y2) {
01428         pixel(x1, y1);
01429     } else {
01430         WriteCommandW(0x91, x1);
01431         WriteCommandW(0x93, y1);
01432         WriteCommandW(0x95, x2);
01433         WriteCommandW(0x97, y2);
01434         unsigned char drawCmd = 0x00;       // Line
01435         WriteCommand(0x90, drawCmd);
01436         WriteCommand(0x90, 0x80 + drawCmd); // Start drawing.
01437         if (!_WaitWhileReg(0x90, 0x80)) {
01438             REGISTERPERFORMANCE(PRF_DRAWLINE);
01439             return external_abort;
01440         }
01441     }
01442     REGISTERPERFORMANCE(PRF_DRAWLINE);
01443     return noerror;
01444 }
01445 
01446 
01447 RetCode_t RA8875::ThickLine(point_t p1, point_t p2, dim_t thickness, color_t color)
01448 {
01449     if (thickness == 1) {
01450         line(p1,p2, color);
01451     } else {
01452         int dx = abs(p2.x-p1.x), sx = p1.x<p2.x ? 1 : -1;
01453         int dy = abs(p2.y-p1.y), sy = p1.y<p2.y ? 1 : -1;
01454         int err = (dx>dy ? dx : -dy)/2, e2;
01455         
01456         for (;;) {
01457             fillcircle(p1.x, p1.y, thickness/2, color);
01458             if (p1.x==p2.x && p1.y==p2.y) 
01459                 break;
01460             e2 = err;
01461             if (e2 >-dx) 
01462                 { err -= dy; p1.x += sx; }
01463             if (e2 < dy) 
01464                 { err += dx; p1.y += sy; }
01465         }        
01466     }
01467     return noerror;
01468 }
01469 
01470 
01471 //
01472 // Rectangle functions all mostly helpers to the basic rectangle function
01473 //
01474 
01475 RetCode_t RA8875::fillrect(rect_t r, color_t color, fill_t fillit)
01476 {
01477     return rect(r.p1.x, r.p1.y, r.p2.x, r.p2.y, color, fillit);
01478 }
01479 
01480 RetCode_t RA8875::fillrect(loc_t x1, loc_t y1, loc_t x2, loc_t y2,
01481                            color_t color, fill_t fillit)
01482 {
01483     return rect(x1,y1,x2,y2,color,fillit);
01484 }
01485 
01486 RetCode_t RA8875::rect(rect_t r, color_t color, fill_t fillit)
01487 {
01488     return rect(r.p1.x, r.p1.y, r.p2.x, r.p2.y, color, fillit);
01489 }
01490 
01491 RetCode_t RA8875::rect(loc_t x1, loc_t y1, loc_t x2, loc_t y2,
01492                        color_t color, fill_t fillit)
01493 {
01494     foreground(color);
01495     return rect(x1,y1,x2,y2,fillit);
01496 }
01497 
01498 RetCode_t RA8875::rect(loc_t x1, loc_t y1, loc_t x2, loc_t y2,
01499                        fill_t fillit)
01500 {
01501     RetCode_t ret = noerror;
01502     PERFORMANCE_RESET;
01503     // check for bad_parameter
01504     if (x1 < 0 || x1 >= screenwidth || x2 < 0 || x2 >= screenwidth 
01505     || y1 < 0 || y1 >= screenheight || y2 < 0 || y2 >= screenheight) {
01506         ret = bad_parameter;
01507     } else {
01508         if (x1 == x2 && y1 == y2) {
01509             pixel(x1, y1);
01510         } else if (x1 == x2) {
01511             line(x1, y1, x2, y2);
01512         } else if (y1 == y2) {
01513             line(x1, y1, x2, y2);
01514         } else {
01515             WriteCommandW(0x91, x1);
01516             WriteCommandW(0x93, y1);
01517             WriteCommandW(0x95, x2);
01518             WriteCommandW(0x97, y2);
01519             unsigned char drawCmd = 0x10;   // Rectangle
01520             if (fillit == FILL)
01521                 drawCmd |= 0x20;
01522             WriteCommand(0x90, drawCmd);
01523             ret = WriteCommand(0x90, 0x80 + drawCmd); // Start drawing.
01524             if (!_WaitWhileReg(0x90, 0x80)) {
01525                 REGISTERPERFORMANCE(PRF_DRAWRECTANGLE);
01526                 return external_abort;
01527             }
01528         }
01529     }
01530     REGISTERPERFORMANCE(PRF_DRAWRECTANGLE);
01531     return ret;
01532 }
01533 
01534 
01535 //
01536 // rounded rectangle functions are mostly helpers to the base round rect
01537 //
01538 
01539 RetCode_t RA8875::fillroundrect(rect_t r, dim_t radius1, dim_t radius2, color_t color, fill_t fillit)
01540 {
01541     return roundrect(r.p1.x, r.p1.y, r.p2.x, r.p2.y, radius1, radius2, color, fillit);
01542 }
01543 
01544 RetCode_t RA8875::fillroundrect(loc_t x1, loc_t y1, loc_t x2, loc_t y2,
01545                                 dim_t radius1, dim_t radius2, color_t color, fill_t fillit)
01546 {
01547     foreground(color);
01548     return roundrect(x1,y1,x2,y2,radius1,radius2,fillit);
01549 }
01550 
01551 RetCode_t RA8875::roundrect(rect_t r, dim_t radius1, dim_t radius2, color_t color, fill_t fillit)
01552 {
01553     return roundrect(r.p1.x, r.p1.y, r.p2.x, r.p2.y, radius1, radius2, color, fillit);
01554 }
01555 
01556 RetCode_t RA8875::roundrect(loc_t x1, loc_t y1, loc_t x2, loc_t y2,
01557                             dim_t radius1, dim_t radius2, color_t color, fill_t fillit)
01558 {
01559     foreground(color);
01560     return roundrect(x1,y1,x2,y2,radius1,radius2,fillit);
01561 }
01562 
01563 
01564 RetCode_t RA8875::roundrect(loc_t x1, loc_t y1, loc_t x2, loc_t y2,
01565                             dim_t radius1, dim_t radius2, fill_t fillit)
01566 {
01567     RetCode_t ret = noerror;
01568 
01569     PERFORMANCE_RESET;
01570     if (x1 < 0 || x1 >= screenwidth || x2 < 0 || x2 >= screenwidth 
01571     || y1 < 0 || y1 >= screenheight || y2 < 0 || y2 >= screenheight) {
01572         ret = bad_parameter;
01573     } else if (x1 > x2 || y1 > y2 || (radius1 > (x2-x1)/2) || (radius2 > (y2-y1)/2) ) {
01574         ret = bad_parameter;
01575     } else if (x1 == x2 && y1 == y2) {
01576         pixel(x1, y1);
01577     } else if (x1 == x2) {
01578         line(x1, y1, x2, y2);
01579     } else if (y1 == y2) {
01580         line(x1, y1, x2, y2);
01581     } else {
01582         WriteCommandW(0x91, x1);
01583         WriteCommandW(0x93, y1);
01584         WriteCommandW(0x95, x2);
01585         WriteCommandW(0x97, y2);
01586         WriteCommandW(0xA1, radius1);
01587         WriteCommandW(0xA3, radius2);
01588         // Should not need this...
01589         WriteCommandW(0xA5, 0);
01590         WriteCommandW(0xA7, 0);
01591         unsigned char drawCmd = 0x20;       // Rounded Rectangle
01592         if (fillit == FILL)
01593             drawCmd |= 0x40;
01594         WriteCommand(0xA0, drawCmd);
01595         WriteCommand(0xA0, 0x80 + drawCmd); // Start drawing.
01596         if (!_WaitWhileReg(0xA0, 0x80)) {
01597             REGISTERPERFORMANCE(PRF_DRAWROUNDEDRECTANGLE);
01598             return external_abort;
01599         }
01600     }
01601     REGISTERPERFORMANCE(PRF_DRAWROUNDEDRECTANGLE);
01602     return ret;
01603 }
01604 
01605 
01606 //
01607 // triangle functions
01608 //
01609 
01610 RetCode_t RA8875::triangle(loc_t x1, loc_t y1, loc_t x2, loc_t y2,
01611                            loc_t x3, loc_t y3, color_t color, fill_t fillit)
01612 {
01613     RetCode_t ret;
01614 
01615     if (x1 < 0 || x1 >= screenwidth || x2 < 0 || x2 >= screenwidth || x3 < 0 || x3 >= screenwidth
01616     || y1 < 0 || y1 >= screenheight || y2 < 0 || y2 >= screenheight || y3 < 0 || y3 >= screenheight)
01617         ret = bad_parameter;
01618     foreground(color);
01619     ret = triangle(x1,y1,x2,y2,x3,y3,fillit);
01620     return ret;
01621 }
01622 
01623 
01624 RetCode_t RA8875::filltriangle(loc_t x1, loc_t y1, loc_t x2, loc_t y2,
01625                                loc_t x3, loc_t y3, color_t color, fill_t fillit)
01626 {
01627     RetCode_t ret;
01628 
01629     foreground(color);
01630     ret = triangle(x1,y1,x2,y2,x3,y3,fillit);
01631     return ret;
01632 }
01633 
01634 
01635 RetCode_t RA8875::triangle(loc_t x1, loc_t y1 ,loc_t x2, loc_t y2,
01636                            loc_t x3, loc_t y3, fill_t fillit)
01637 {
01638     RetCode_t ret = noerror;
01639 
01640     PERFORMANCE_RESET;
01641     if (x1 == x2 && y1 == y2 && x1 == x3 && y1 == y3) {
01642         pixel(x1, y1);
01643     } else {
01644         WriteCommandW(0x91, x1);
01645         WriteCommandW(0x93, y1);
01646         WriteCommandW(0x95, x2);
01647         WriteCommandW(0x97, y2);
01648         WriteCommandW(0xA9, x3);
01649         WriteCommandW(0xAB, y3);
01650         unsigned char drawCmd = 0x01;       // Triangle
01651         if (fillit == FILL)
01652             drawCmd |= 0x20;
01653         WriteCommand(0x90, drawCmd);
01654         WriteCommand(0x90, 0x80 + drawCmd); // Start drawing.
01655         if (!_WaitWhileReg(0x90, 0x80)) {
01656             REGISTERPERFORMANCE(PRF_DRAWTRIANGLE);
01657             return external_abort;
01658         }
01659     }
01660     REGISTERPERFORMANCE(PRF_DRAWTRIANGLE);
01661     return ret;
01662 }
01663 
01664 
01665 RetCode_t RA8875::circle(point_t p, dim_t radius,
01666                          color_t color, fill_t fillit)
01667 {
01668     foreground(color);
01669     return circle(p.x,p.y,radius,fillit);
01670 }
01671 
01672 
01673 RetCode_t RA8875::fillcircle(point_t p, dim_t radius,
01674                              color_t color, fill_t fillit)
01675 {
01676     foreground(color);
01677     return circle(p.x,p.y,radius,fillit);
01678 }
01679 
01680 
01681 RetCode_t RA8875::circle(point_t p, dim_t radius, fill_t fillit)
01682 {
01683     return circle(p.x,p.y,radius,fillit);
01684 }
01685 
01686 
01687 RetCode_t RA8875::circle(loc_t x, loc_t y, dim_t radius,
01688                          color_t color, fill_t fillit)
01689 {
01690     foreground(color);
01691     return circle(x,y,radius,fillit);
01692 }
01693 
01694 
01695 RetCode_t RA8875::fillcircle(loc_t x, loc_t y, dim_t radius,
01696                              color_t color, fill_t fillit)
01697 {
01698     foreground(color);
01699     return circle(x,y,radius,fillit);
01700 }
01701 
01702 
01703 RetCode_t RA8875::circle(loc_t x, loc_t y, dim_t radius, fill_t fillit)
01704 {
01705     RetCode_t ret = noerror;
01706 
01707     PERFORMANCE_RESET;
01708     if (radius <= 0 || (x - radius) < 0 || (x + radius) > screenwidth 
01709     || (y - radius) < 0 || (y + radius) > screenheight) {
01710         ret = bad_parameter;
01711     } else if (radius == 1) {
01712         pixel(x,y);
01713     } else {
01714         WriteCommandW(0x99, x);
01715         WriteCommandW(0x9B, y);
01716         WriteCommand(0x9d, radius & 0xFF);
01717         unsigned char drawCmd = 0x00;       // Circle
01718         if (fillit == FILL)
01719             drawCmd |= 0x20;
01720         WriteCommand(0x90, drawCmd);
01721         WriteCommand(0x90, 0x40 + drawCmd); // Start drawing.
01722         if (!_WaitWhileReg(0x90, 0x40)) {
01723             REGISTERPERFORMANCE(PRF_DRAWCIRCLE);
01724             return external_abort;
01725         }
01726     }
01727     REGISTERPERFORMANCE(PRF_DRAWCIRCLE);
01728     return ret;
01729 }
01730 
01731 
01732 RetCode_t RA8875::ellipse(loc_t x, loc_t y, dim_t radius1, dim_t radius2, color_t color, fill_t fillit)
01733 {
01734     foreground(color);
01735     return ellipse(x,y,radius1,radius2,fillit);
01736 }
01737 
01738 
01739 RetCode_t RA8875::fillellipse(loc_t x, loc_t y, dim_t radius1, dim_t radius2, color_t color, fill_t fillit)
01740 {
01741     foreground(color);
01742     return ellipse(x,y,radius1,radius2,fillit);
01743 }
01744 
01745 
01746 RetCode_t RA8875::ellipse(loc_t x, loc_t y, dim_t radius1, dim_t radius2, fill_t fillit)
01747 {
01748     RetCode_t ret = noerror;
01749 
01750     PERFORMANCE_RESET;
01751     if (radius1 <= 0 || radius2 <= 0 || (x - radius1) < 0 || (x + radius1) > screenwidth 
01752     || (y - radius2) < 0 || (y + radius2) > screenheight) {
01753         ret = bad_parameter;
01754     } else if (radius1 == 1 && radius2 == 1) {
01755         pixel(x, y);
01756     } else {
01757         WriteCommandW(0xA5, x);
01758         WriteCommandW(0xA7, y);
01759         WriteCommandW(0xA1, radius1);
01760         WriteCommandW(0xA3, radius2);
01761         unsigned char drawCmd = 0x00;   // Ellipse
01762         if (fillit == FILL)
01763             drawCmd |= 0x40;
01764         WriteCommand(0xA0, drawCmd);
01765         WriteCommand(0xA0, 0x80 + drawCmd); // Start drawing.
01766         if (!_WaitWhileReg(0xA0, 0x80)) {
01767             REGISTERPERFORMANCE(PRF_DRAWELLIPSE);
01768             return external_abort;
01769         }
01770     }
01771     REGISTERPERFORMANCE(PRF_DRAWELLIPSE);
01772     return ret;
01773 }
01774 
01775 
01776 RetCode_t RA8875::frequency(unsigned long Hz, unsigned long Hz2)
01777 {
01778     spiwritefreq = Hz;
01779     if (Hz2 != 0)
01780         spireadfreq = Hz2;
01781     else
01782         spireadfreq = Hz/2;
01783     _setWriteSpeed(true);
01784     //       __   ___
01785     // Clock   ___A     Rising edge latched
01786     //       ___ ____
01787     // Data  ___X____
01788     spi.format(8, 3);           // 8 bits and clock to data phase 0
01789     return noerror;
01790 }
01791 
01792 void RA8875::_setWriteSpeed(bool writeSpeed)
01793 {
01794     if (writeSpeed) {
01795         spi.frequency(spiwritefreq);
01796         spiWriteSpeed = true;
01797     } else {
01798         spi.frequency(spireadfreq);
01799         spiWriteSpeed = false;
01800     }
01801 }
01802 
01803 
01804 
01805 RetCode_t RA8875::BlockMove(uint8_t dstLayer, uint8_t dstDataSelect, point_t dstPoint,
01806     uint8_t srcLayer, uint8_t srcDataSelect, point_t srcPoint,
01807     dim_t bte_width, dim_t bte_height,
01808     uint8_t bte_op_code, uint8_t bte_rop_code)
01809 {
01810     uint8_t cmd;
01811 
01812     PERFORMANCE_RESET;
01813     ///@todo range check and error return rather than to secretly fix
01814     srcPoint.x &= 0x3FF;    // prevent high bits from doing unexpected things
01815     srcPoint.y &= 0x1FF;
01816     dstPoint.x &= 0x3FF;
01817     dstPoint.y &= 0x1FF;
01818     WriteCommandW(0x54, srcPoint.x);
01819     WriteCommandW(0x56, ((dim_t)(srcLayer & 1) << 15) | srcPoint.y);
01820     WriteCommandW(0x58, dstPoint.x);
01821     WriteCommandW(0x5A, ((dim_t)(dstLayer & 1) << 15) | dstPoint.y);
01822     WriteCommandW(0x5C, bte_width);
01823     WriteCommandW(0x5E, bte_height);
01824     WriteCommand(0x51,  ((bte_rop_code & 0x0F) << 4) | (bte_op_code & 0x0F));
01825     cmd = ((srcDataSelect & 1) << 6) | ((dstDataSelect & 1) << 5);
01826     WriteCommand(0x50, 0x80 | cmd);     // enable the BTE
01827     if (!_WaitWhileBusy(0x40)) {
01828         REGISTERPERFORMANCE(PRF_BLOCKMOVE);
01829         return external_abort;
01830     }
01831     REGISTERPERFORMANCE(PRF_BLOCKMOVE);
01832     return noerror;
01833 }
01834 
01835 
01836 RetCode_t RA8875::Power(bool on)
01837 {
01838     WriteCommand(0x01, (on) ? 0x80 : 0x00);
01839     return noerror;
01840 }
01841 
01842 
01843 RetCode_t RA8875::Backlight_u8(uint8_t brightness)
01844 {
01845     static bool is_enabled = false;
01846     
01847     if (brightness == 0) {
01848         WriteCommand(0x8a); // Disable the PWM
01849         WriteData(0x00);
01850         is_enabled = false;
01851     } else if (!is_enabled) {
01852         WriteCommand(0x8a); // Enable the PWM
01853         WriteData(0x80);
01854         WriteCommand(0x8a); // Not sure why this is needed, but following the pattern
01855         WriteData(0x81);    // open PWM (SYS_CLK / 2 as best I can tell)
01856         is_enabled = true;
01857     }
01858     WriteCommand(0x8b, brightness);  // Brightness parameter 0xff-0x00
01859     return noerror;
01860 }
01861 
01862 uint8_t RA8875::GetBacklight_u8(void)
01863 {
01864     return ReadCommand(0x8b);
01865 }
01866 
01867 RetCode_t RA8875::Backlight(float brightness)
01868 {
01869     unsigned char b;
01870 
01871     if (brightness >= 1.0f)
01872         b = 255;
01873     else if (brightness <= 0.0f)
01874         b = 0;
01875     else
01876         b = (unsigned char)(brightness * 255);
01877     return Backlight_u8(b);
01878 }
01879 
01880 float RA8875::GetBacklight(void)
01881 {
01882     return (float)(GetBacklight_u8())/255;
01883 }
01884 
01885 RetCode_t RA8875::SelectUserFont(const uint8_t * _font)
01886 {
01887     INFO("Cursor(%d,%d)  %p", cursor_x, cursor_y, _font);
01888     INFO("Text C(%d,%d)", GetTextCursor_X(), GetTextCursor_Y());
01889     if (_font) {
01890         HexDump("Font Memory", _font, 16);
01891         extFontHeight = _font[6];
01892         uint32_t totalWidth = 0;
01893         uint16_t firstChar = _font[3] * 256 + _font[2];
01894         uint16_t lastChar  = _font[5] * 256 + _font[4];
01895         uint16_t i;
01896         
01897         for (i=firstChar; i<=lastChar; i++) {
01898             // 8 bytes of preamble to the first level lookup table
01899             uint16_t offsetToCharLookup = 8 + 4 * (i - firstChar);    // 4-bytes: width(pixels), 16-bit offset from table start, 0
01900             totalWidth += _font[offsetToCharLookup];
01901         }
01902         extFontWidth = totalWidth / (lastChar - firstChar);
01903         INFO("Font Metrics: Avg W: %2d, H: %2d, First:%d, Last:%d", extFontWidth, extFontHeight, firstChar, lastChar);
01904     }
01905     SetTextCursor(GetTextCursor_X(), GetTextCursor_Y());  // soft-font cursor -> hw cursor
01906     font = _font;
01907     return GraphicsDisplay::SelectUserFont(_font);
01908 }
01909 
01910 RetCode_t RA8875::background(color_t color)
01911 {
01912     GraphicsDisplay::background(color);
01913     return _writeColorTrio(0x60, color);
01914 }
01915 
01916 
01917 RetCode_t RA8875::background(unsigned char r, unsigned char g, unsigned char b)
01918 {
01919     background(RGB(r,g,b));
01920     return noerror;
01921 }
01922 
01923 
01924 RetCode_t RA8875::foreground(color_t color)
01925 {
01926     GraphicsDisplay::foreground(color);
01927     return _writeColorTrio(0x63, color);
01928 }
01929 
01930 
01931 RetCode_t RA8875::foreground(unsigned char r, unsigned char g, unsigned char b)
01932 {
01933     foreground(RGB(r,g,b));
01934     return noerror;
01935 }
01936 
01937 
01938 color_t RA8875::GetForeColor(void)
01939 {
01940     return _readColorTrio(0x63);
01941 }
01942 
01943 
01944 color_t RA8875::DOSColor(int i)
01945 {
01946     const color_t colors[16] = {
01947         Black,    Blue,       Green,       Cyan,
01948         Red,      Magenta,    Brown,       Gray,
01949         Charcoal, BrightBlue, BrightGreen, BrightCyan,
01950         Orange,   Pink,       Yellow,      White
01951     };
01952     if (i >= 0 && i < 16)
01953         return colors[i];
01954     else
01955         return 0;
01956 }
01957 
01958 
01959 const char * RA8875::DOSColorNames(int i)
01960 {
01961     const char * names[16] = {
01962         "Black",    "Blue",       "Green",       "Cyan",
01963         "Red",      "Magenta",    "Brown",       "Gray",
01964         "Charcoal", "BrightBlue", "BrightGreen", "BrightCyan",
01965         "Orange",   "Pink",       "Yellow",      "White"
01966     };
01967     if (i >= 0 && i < 16)
01968         return names[i];
01969     else
01970         return NULL;
01971 }
01972 
01973 
01974 ///////////////////////////////////////////////////////////////
01975 // Private functions
01976 
01977 unsigned char RA8875::_spiwrite(unsigned char data)
01978 {
01979     unsigned char retval;
01980 
01981     if (!spiWriteSpeed)
01982         _setWriteSpeed(true);
01983     retval = spi.write(data);
01984     return retval;
01985 }
01986 
01987 
01988 unsigned char RA8875::_spiread(void)
01989 {
01990     unsigned char retval;
01991     unsigned char data = 0;
01992 
01993     if (spiWriteSpeed)
01994         _setWriteSpeed(false);
01995     retval = spi.write(data);
01996     return retval;
01997 }
01998 
01999 
02000 RetCode_t RA8875::_select(bool chipsel)
02001 {
02002     cs = (chipsel == true) ? 0 : 1;
02003     return noerror;
02004 }
02005 
02006 
02007 RetCode_t RA8875::PrintScreen(uint16_t layer, loc_t x, loc_t y, dim_t w, dim_t h, const char *Name_BMP)
02008 {
02009     (void)layer;
02010     
02011     // AttachPrintHandler(this, RA8875::_printCallback);
02012     // return PrintScreen(x,y,w,h);
02013     return PrintScreen(x, y, w, h, Name_BMP);
02014 }
02015 
02016 RetCode_t RA8875::_printCallback(RA8875::filecmd_t cmd, uint8_t * buffer, uint16_t size)
02017 {
02018     HexDump("CB", buffer, size);
02019     switch(cmd) {
02020         case RA8875::OPEN:
02021             //pc.printf("About to write %lu bytes\r\n", *(uint32_t *)buffer);
02022             _printFH = fopen("file.bmp", "w+b");
02023             if (_printFH == 0)
02024                 return file_not_found;
02025             break;
02026         case RA8875::WRITE:
02027             //pc.printf("  Write %4u bytes\r\n", size);
02028             fwrite(buffer, 1, size, _printFH);
02029             break;
02030         case RA8875::CLOSE:
02031             //pc.printf("  close\r\n");
02032             fclose(_printFH);
02033             _printFH = 0;
02034             break;
02035         default:
02036             //pc.printf("Unexpected callback %d\r\n", cmd);
02037             return file_not_found;
02038             //break;
02039     }
02040     return noerror;
02041 }
02042 
02043 RetCode_t RA8875::PrintScreen(loc_t x, loc_t y, dim_t w, dim_t h)
02044 {
02045     BITMAPFILEHEADER BMP_Header;
02046     BITMAPINFOHEADER BMP_Info;
02047     uint8_t * lineBuffer = NULL;
02048     color_t * pixelBuffer = NULL;
02049     color_t * pixelBuffer2 = NULL;
02050     
02051     INFO("(%d,%d) - (%d,%d)", x,y,w,h);
02052     if (x >= 0 && x < screenwidth
02053             && y >= 0 && y < screenheight
02054             && w > 0 && x + w <= screenwidth
02055             && h > 0 && y + h <= screenheight) {
02056 
02057         BMP_Header.bfType = BF_TYPE;
02058         BMP_Header.bfSize = (w * h * sizeof(RGBQUAD)) + sizeof(BMP_Header) + sizeof(BMP_Header);
02059         BMP_Header.bfReserved1 = 0;
02060         BMP_Header.bfReserved2 = 0;
02061         BMP_Header.bfOffBits = sizeof(BMP_Header) + sizeof(BMP_Header);
02062 
02063         BMP_Info.biSize = sizeof(BMP_Info);
02064         BMP_Info.biWidth = w;
02065         BMP_Info.biHeight = h;
02066         BMP_Info.biPlanes = 1;
02067         BMP_Info.biBitCount = 24;
02068         BMP_Info.biCompression = BI_RGB;
02069         BMP_Info.biSizeImage = 0;
02070         BMP_Info.biXPelsPerMeter = 0;
02071         BMP_Info.biYPelsPerMeter = 0;
02072         BMP_Info.biClrUsed = 0;
02073         BMP_Info.biClrImportant = 0;
02074 
02075         // Allocate the memory we need to proceed
02076         int lineBufSize = ((24 * w + 7)/8);
02077         lineBuffer = (uint8_t *)swMalloc(lineBufSize);
02078         if (lineBuffer == NULL) {
02079             ERR("Not enough RAM for PrintScreen lineBuffer");
02080             return(not_enough_ram);
02081         }
02082 
02083         #define DOUBLEBUF /* one larger buffer instead of two */
02084         
02085         #ifdef DOUBLEBUF
02086         // In the "#else", pixelBuffer2 malloc returns a value, 
02087         // but is actually causing a failure later. 
02088         // This test helps determine if it is truly out of memory,
02089         // or if malloc is broken.
02090         pixelBuffer = (color_t *)swMalloc(2 * w * sizeof(color_t));
02091         pixelBuffer2 = pixelBuffer + (w * sizeof(color_t));
02092         #else
02093         pixelBuffer = (color_t *)swMalloc(w * sizeof(color_t));
02094         pixelBuffer2 = (color_t *)swMalloc(w * sizeof(color_t));
02095         #endif
02096         if (pixelBuffer == NULL || pixelBuffer2 == NULL) {
02097             ERR("Not enough RAM for pixelBuffer");
02098             #ifndef DOUBLEBUF
02099             if (pixelBuffer2)
02100                 swFree(pixelBuffer2);
02101             #endif
02102             if (pixelBuffer)
02103                 swFree(pixelBuffer);
02104             swFree(lineBuffer);
02105             return(not_enough_ram);
02106         }
02107 
02108         // Get the file primed...
02109         privateCallback(OPEN, (uint8_t *)&BMP_Header.bfSize, 4);
02110 
02111         // Be optimistic - don't check for errors.
02112         HexDump("BMP_Header", (uint8_t *)&BMP_Header, sizeof(BMP_Header));        
02113         //fwrite(&BMP_Header, sizeof(char), sizeof(BMP_Header), Image);
02114         privateCallback(WRITE, (uint8_t *)&BMP_Header, sizeof(BMP_Header));
02115 
02116         HexDump("BMP_Info", (uint8_t *)&BMP_Info, sizeof(BMP_Info));
02117         //fwrite(&BMP_Info, sizeof(char), sizeof(BMP_Info), Image);
02118         privateCallback(WRITE, (uint8_t *)&BMP_Info, sizeof(BMP_Info));
02119 
02120         //color_t transparency = GetBackgroundTransparencyColor();
02121         LayerMode_T ltpr0 = GetLayerMode();
02122 
02123         uint16_t prevLayer = GetDrawingLayer();
02124         // If only one of the layers is visible, select that layer
02125         switch(ltpr0) {
02126             case ShowLayer0:
02127                 SelectDrawingLayer(0);
02128                 break;
02129             case ShowLayer1:
02130                 SelectDrawingLayer(1);
02131                 break;
02132             default:
02133                 break;
02134         }
02135 
02136         // Read the display from the last line toward the top
02137         // so we can write the file in one pass.
02138         for (int j = h - 1; j >= 0; j--) {
02139             if (idle_callback) {
02140                 (*idle_callback)(progress, (h - 1 - j) * 100 / (h - 1));
02141             }
02142 
02143             if (ltpr0 >= 2)             // Need to combine the layers...
02144                 SelectDrawingLayer(0);  // so read layer 0 first
02145             // Read one line of pixels to a local buffer
02146             if (getPixelStream(pixelBuffer, w, x,y+j) != noerror) {
02147                 ERR("getPixelStream error, and no recovery handler...");
02148             }
02149             if (ltpr0 >= 2) {           // Need to combine the layers...
02150                 SelectDrawingLayer(1);  // so read layer 1 next
02151                 if (getPixelStream(pixelBuffer2, w, x,y+j) != noerror) {
02152                     ERR("getPixelStream error, and no recovery handler...");
02153                 }
02154             }
02155             INFO("1st Color: %04X", pixelBuffer[0]);
02156             HexDump("Raster", (uint8_t *)pixelBuffer, w);
02157             // Convert the local buffer to RGBQUAD format
02158             int lb = 0;
02159             for (int i=0; i<w; i++) {
02160                 RGBQUAD q0 = RGB16ToRGBQuad(pixelBuffer[x+i]);      // Scale to 24-bits
02161                 RGBQUAD q1 = RGB16ToRGBQuad(pixelBuffer2[x+i]);     // Scale to 24-bits
02162                 switch (ltpr0) {
02163                     case 0:
02164                     case 1:
02165                     case 2: // lighten-overlay  (@TODO Not supported yet)
02166                     case 6: // Floating Windows     (@TODO not sure how to support)
02167                     default: // Reserved...
02168                         lineBuffer[lb++] = q0.rgbBlue;
02169                         lineBuffer[lb++] = q0.rgbGreen;
02170                         lineBuffer[lb++] = q0.rgbRed;
02171                         break;
02172                     case 3: // transparent mode (@TODO Read the background color register for transparent)
02173                     case 4: // boolean or
02174                         lineBuffer[lb++] = q0.rgbBlue | q1.rgbBlue;
02175                         lineBuffer[lb++] = q0.rgbGreen | q1.rgbGreen;
02176                         lineBuffer[lb++] = q0.rgbRed | q1.rgbRed;
02177                         break;
02178                     case 5: // boolean AND
02179                         lineBuffer[lb++] = q0.rgbBlue & q1.rgbBlue;
02180                         lineBuffer[lb++] = q0.rgbGreen & q1.rgbGreen;
02181                         lineBuffer[lb++] = q0.rgbRed & q1.rgbRed;
02182                         break;
02183                 }
02184             }
02185             if (j == h - 1) {
02186                 HexDump("Line", lineBuffer, lineBufSize);
02187             }
02188             // Write to disk
02189             //fwrite(lineBuffer, sizeof(char), lb, Image);
02190             privateCallback(WRITE, (uint8_t *)lineBuffer, lb);
02191         }
02192         SelectDrawingLayer(prevLayer);
02193         //fclose(Image);
02194         privateCallback(CLOSE, NULL, 0);
02195         
02196         #ifndef DOUBLEBUF
02197         if (pixelBuffer2)
02198             swFree(pixelBuffer2);
02199         #endif
02200         if (pixelBuffer)
02201             swFree(pixelBuffer);
02202         swFree(lineBuffer);
02203         INFO("Image closed");
02204         return noerror;
02205     } else {
02206         return bad_parameter;
02207     }
02208 }
02209 
02210 RetCode_t RA8875::PrintScreen(loc_t x, loc_t y, dim_t w, dim_t h, const char *Name_BMP)
02211 {
02212     BITMAPFILEHEADER BMP_Header;
02213     BITMAPINFOHEADER BMP_Info;
02214     uint8_t * lineBuffer = NULL;
02215     color_t * pixelBuffer = NULL;
02216     color_t * pixelBuffer2 = NULL;
02217     
02218     INFO("(%d,%d) - (%d,%d) %s", x,y,w,h,Name_BMP);
02219     if (x >= 0 && x < screenwidth
02220             && y >= 0 && y < screenheight
02221             && w > 0 && x + w <= screenwidth
02222             && h > 0 && y + h <= screenheight) {
02223 
02224         BMP_Header.bfType = BF_TYPE;
02225         BMP_Header.bfSize = (w * h * sizeof(RGBQUAD)) + sizeof(BMP_Header) + sizeof(BMP_Header);
02226         BMP_Header.bfReserved1 = 0;
02227         BMP_Header.bfReserved2 = 0;
02228         BMP_Header.bfOffBits = sizeof(BMP_Header) + sizeof(BMP_Header);
02229 
02230         BMP_Info.biSize = sizeof(BMP_Info);
02231         BMP_Info.biWidth = w;
02232         BMP_Info.biHeight = h;
02233         BMP_Info.biPlanes = 1;
02234         BMP_Info.biBitCount = 24;
02235         BMP_Info.biCompression = BI_RGB;
02236         BMP_Info.biSizeImage = 0;
02237         BMP_Info.biXPelsPerMeter = 0;
02238         BMP_Info.biYPelsPerMeter = 0;
02239         BMP_Info.biClrUsed = 0;
02240         BMP_Info.biClrImportant = 0;
02241 
02242         // Allocate the memory we need to proceed
02243         int lineBufSize = ((24 * w + 7)/8);
02244         lineBuffer = (uint8_t *)swMalloc(lineBufSize);
02245         if (lineBuffer == NULL) {
02246             ERR("Not enough RAM for PrintScreen lineBuffer");
02247             return(not_enough_ram);
02248         }
02249 
02250         #define DOUBLEBUF /* one larger buffer instead of two */
02251         
02252         #ifdef DOUBLEBUF
02253         // In the "#else", pixelBuffer2 malloc returns a value, 
02254         // but is actually causing a failure later. 
02255         // This test helps determine if it is truly out of memory,
02256         // or if malloc is broken.
02257         pixelBuffer = (color_t *)swMalloc(2 * w * sizeof(color_t));
02258         pixelBuffer2 = pixelBuffer + (w * sizeof(color_t));
02259         #else
02260         pixelBuffer = (color_t *)swMalloc(w * sizeof(color_t));
02261         pixelBuffer2 = (color_t *)swMalloc(w * sizeof(color_t));
02262         #endif
02263         if (pixelBuffer == NULL || pixelBuffer2 == NULL) {
02264             ERR("Not enough RAM for pixelBuffer");
02265             #ifndef DOUBLEBUF
02266             if (pixelBuffer2)
02267                 swFree(pixelBuffer2);
02268             #endif
02269             if (pixelBuffer)
02270                 swFree(pixelBuffer);
02271             swFree(lineBuffer);
02272             return(not_enough_ram);
02273         }
02274 
02275         FILE *Image = fopen(Name_BMP, "wb");
02276         if (!Image) {
02277             ERR("Can't open file for write");
02278             #ifndef DOUBLEBUF
02279             if (pixelBuffer2)
02280                 swFree(pixelBuffer2);
02281             #endif
02282             if (pixelBuffer)
02283                 swFree(pixelBuffer);
02284             swFree(lineBuffer);
02285             return(file_not_found);
02286         }
02287 
02288         // Be optimistic - don't check for errors.
02289         HexDump("BMP_Header", (uint8_t *)&BMP_Header, sizeof(BMP_Header));
02290         fwrite(&BMP_Header, sizeof(char), sizeof(BMP_Header), Image);
02291 
02292         HexDump("BMP_Info", (uint8_t *)&BMP_Info, sizeof(BMP_Info));
02293         fwrite(&BMP_Info, sizeof(char), sizeof(BMP_Info), Image);
02294 
02295         //color_t transparency = GetBackgroundTransparencyColor();
02296         LayerMode_T ltpr0 = GetLayerMode();
02297 
02298         uint16_t prevLayer = GetDrawingLayer();
02299         // If only one of the layers is visible, select that layer
02300         switch(ltpr0) {
02301             case ShowLayer0:
02302                 SelectDrawingLayer(0);
02303                 break;
02304             case ShowLayer1:
02305                 SelectDrawingLayer(1);
02306                 break;
02307             default:
02308                 break;
02309         }
02310 
02311         // Read the display from the last line toward the top
02312         // so we can write the file in one pass.
02313         for (int j = h - 1; j >= 0; j--) {
02314             if (idle_callback) {
02315                 (*idle_callback)(progress, (h - 1 - j) * 100 / (h - 1));
02316             }
02317 
02318             if (ltpr0 >= 2)             // Need to combine the layers...
02319                 SelectDrawingLayer(0);  // so read layer 0 first
02320             // Read one line of pixels to a local buffer
02321             if (getPixelStream(pixelBuffer, w, x,y+j) != noerror) {
02322                 ERR("getPixelStream error, and no recovery handler...");
02323             }
02324             if (ltpr0 >= 2) {           // Need to combine the layers...
02325                 SelectDrawingLayer(1);  // so read layer 1 next
02326                 if (getPixelStream(pixelBuffer2, w, x,y+j) != noerror) {
02327                     ERR("getPixelStream error, and no recovery handler...");
02328                 }
02329             }
02330             INFO("1st Color: %04X", pixelBuffer[0]);
02331             HexDump("Raster", (uint8_t *)pixelBuffer, w);
02332             // Convert the local buffer to RGBQUAD format
02333             int lb = 0;
02334             for (int i=0; i<w; i++) {
02335                 RGBQUAD q0 = RGB16ToRGBQuad(pixelBuffer[x+i]);      // Scale to 24-bits
02336                 RGBQUAD q1 = RGB16ToRGBQuad(pixelBuffer2[x+i]);     // Scale to 24-bits
02337                 switch (ltpr0) {
02338                     case 0:
02339                     case 1:
02340                     case 2: // lighten-overlay  (@TODO Not supported yet)
02341                     case 6: // Floating Windows     (@TODO not sure how to support)
02342                     default: // Reserved...
02343                         lineBuffer[lb++] = q0.rgbBlue;
02344                         lineBuffer[lb++] = q0.rgbGreen;
02345                         lineBuffer[lb++] = q0.rgbRed;
02346                         break;
02347                     case 3: // transparent mode (@TODO Read the background color register for transparent)
02348                     case 4: // boolean or
02349                         lineBuffer[lb++] = q0.rgbBlue | q1.rgbBlue;
02350                         lineBuffer[lb++] = q0.rgbGreen | q1.rgbGreen;
02351                         lineBuffer[lb++] = q0.rgbRed | q1.rgbRed;
02352                         break;
02353                     case 5: // boolean AND
02354                         lineBuffer[lb++] = q0.rgbBlue & q1.rgbBlue;
02355                         lineBuffer[lb++] = q0.rgbGreen & q1.rgbGreen;
02356                         lineBuffer[lb++] = q0.rgbRed & q1.rgbRed;
02357                         break;
02358                 }
02359             }
02360             if (j == h - 1) {
02361                 HexDump("Line", lineBuffer, lineBufSize);
02362             }
02363             // Write to disk
02364             fwrite(lineBuffer, sizeof(char), lb, Image);
02365         }
02366         SelectDrawingLayer(prevLayer);
02367         fclose(Image);
02368         #ifndef DOUBLEBUF
02369         if (pixelBuffer2)
02370             swFree(pixelBuffer2);
02371         #endif
02372         if (pixelBuffer)
02373             swFree(pixelBuffer);
02374         swFree(lineBuffer);
02375         INFO("Image closed");
02376         return noerror;
02377     } else {
02378         return bad_parameter;
02379     }
02380 }
02381 
02382 
02383 // ##########################################################################
02384 // ##########################################################################
02385 // ##########################################################################
02386 
02387 #ifdef TESTENABLE
02388 
02389 #include "BPG_Arial08x08.h"
02390 #include "BPG_Arial20x20.h"
02391 
02392 //      ______________  ______________  ______________  _______________
02393 //     /_____   _____/ /  ___________/ /  ___________/ /_____   ______/
02394 //          /  /      /  /            /  /                  /  /
02395 //         /  /      /  /___         /  /__________        /  /
02396 //        /  /      /  ____/        /__________   /       /  /
02397 //       /  /      /  /                       /  /       /  /
02398 //      /  /      /  /__________  ___________/  /       /  /
02399 //     /__/      /_____________/ /_____________/       /__/
02400 //
02401 //    Everything from here down is test code.
02402 //
02403 bool SuppressSlowStuff = false;
02404 
02405 void TextWrapTest(RA8875 & display, Serial & pc)
02406 {
02407     if (!SuppressSlowStuff)
02408         pc.printf("Text Wrap Test\r\n");
02409     display.background(Black);
02410     display.foreground(Blue);
02411     display.cls();
02412     display.Backlight_u8(255);
02413     display.puts("Text Wrap Test.\r\n");
02414     for (int i=1; i<60; i++) {
02415         display.printf("L%2d\n", i % 17);
02416         if (!SuppressSlowStuff)
02417             wait_ms(100);
02418     }
02419     if (!SuppressSlowStuff)
02420         wait_ms(3000);
02421 }
02422 
02423 
02424 void ShowKey(RA8875 & display, int key)
02425 {
02426     loc_t col, row;
02427     dim_t r1 = 25;
02428     color_t color = (key & 0x80) ? Red : Green;
02429 
02430     key &= 0x7F;        // remove the long-press flag
02431     row = (key - 1) / 5;
02432     col = (key - 1) % 5;
02433     if (col > 5) col = 5;
02434     if (row > 4) row = 4;
02435     display.circle(450 - + (2 * r1) * col, 200 - (2 * r1) * row, r1-2, color, FILL);
02436 }
02437 
02438 void HideKey(RA8875 & display, int key)
02439 {
02440     loc_t col, row;
02441     dim_t r1 = 25;
02442 
02443     row = (key - 1) / 5;
02444     col = (key - 1) % 5;
02445     if (col > 5) col = 5;
02446     if (row > 4) row = 4;
02447     display.background(Black);
02448     display.circle(450 - (2 * r1) * col, 200 - (2 * r1) * row, r1-2, Black, FILL);
02449     display.circle(450 - (2 * r1) * col, 200 - (2 * r1) * row, r1-2, Blue);
02450 }
02451 
02452 void KeyPadTest(RA8875 & display, Serial & pc)
02453 {
02454     const uint8_t myMap[22] = {
02455         0,
02456         'a', 'b', 'c', 'd', 'e',
02457         'f', 'g', 'h', 'i', 'j',
02458         'k', 'l', 'm', 'n', 'o',
02459         'p', 'q', 'r', 's', 't',
02460         'x'
02461     };
02462 
02463     display.background(Black);
02464     display.foreground(Blue);
02465     display.cls();
02466     display.Backlight_u8(255);
02467     display.puts("KeyPad Test. Touch the keypad...");
02468     pc.printf("\r\n"
02469               "Raw KeyPad Test. Keypad returns the key-number.\r\n"
02470               "Press [most] any PC keyboard key to advance to next test.\r\n");
02471     RetCode_t ret = display.KeypadInit(true, true, 3, 7, 3);
02472     if (ret != noerror)
02473         pc.printf("returncode from KeypadInit is %d\r\n", ret);
02474     int lastKey = 0;
02475     while (!pc.readable()) {
02476         if (display.readable()) {
02477             int key = display.getc();
02478             if (key) {
02479                 if (((key & 0x7F) != lastKey) && (lastKey != 0))
02480                     HideKey(display, lastKey);
02481                 ShowKey(display, key);
02482                 lastKey = key & 0x7F;
02483             } else {
02484                 // erase the last one
02485                 if (lastKey)
02486                     HideKey(display, lastKey);
02487             }
02488         }
02489     }
02490     (void)pc.getc();
02491     pc.printf("\r\n"
02492               "Map KeyPad Test. Keypad returns the remapped key 'a' - 't'.\r\n"
02493               "Press [most] any PC keyboard key to advance to exit test.\r\n");
02494     display.SetKeyMap(myMap);
02495     while (!pc.readable()) {
02496         if (display.readable()) {
02497             int key = display.getc();
02498             bool longPress = key & 0x80;
02499             display.SetTextCursor(0, 120);
02500             display.printf("Long Press: %d\r\n", longPress);
02501             display.printf("  Remapped: %c %02X\r\n", (key) ? key & 0x7F : ' ', key);
02502         }
02503     }
02504     (void)pc.getc();
02505     display.SetKeyMap();
02506     pc.printf("\r\n");
02507 }
02508 
02509 void TextCursorTest(RA8875 & display, Serial & pc)
02510 {
02511     const char * iCursor  = "The I-Beam cursor should be visible for this text.\r\n";
02512     const char * uCursor  = "The Underscore cursor should be visible for this text.\r\n";
02513     const char * bCursor  = "The Block cursor should be visible for this text.\r\n";
02514     const char * bbCursor = "The Blinking Block cursor should be visible for this text.\r\n";
02515     const char * p;
02516     int delay = 60;
02517 
02518     if (!SuppressSlowStuff)
02519         pc.printf("Text Cursor Test\r\n");
02520     else
02521         delay = 0;
02522     display.background(Black);
02523     display.foreground(Blue);
02524     display.cls();
02525     display.Backlight_u8(255);
02526     display.puts("Text Cursor Test.");
02527 
02528     // visible, non-blinking
02529     display.SetTextCursor(0,20);
02530     display.SetTextCursorControl(RA8875::IBEAM, false);
02531     p = iCursor;
02532     while (*p) {
02533         display._putc(*p++);
02534         wait_ms(delay);
02535     }
02536 
02537     display.SetTextCursorControl(RA8875::UNDER, false);
02538     p = uCursor;
02539     while (*p) {
02540         display._putc(*p++);
02541         wait_ms(delay);
02542     }
02543 
02544     display.SetTextCursorControl(RA8875::BLOCK, false);
02545     p = bCursor;
02546     while (*p) {
02547         display._putc(*p++);
02548         wait_ms(delay);
02549     }
02550 
02551     display.SetTextCursorControl(RA8875::BLOCK, true);
02552     p = bbCursor;
02553     while (*p) {
02554         display._putc(*p++);
02555         wait_ms(delay);
02556     }
02557     wait_ms(delay * 20);
02558     display.SetTextCursorControl(RA8875::NOCURSOR, false);
02559 }
02560 
02561 
02562 void BacklightTest(RA8875 & display, Serial & pc, float ramptime)
02563 {
02564     char buf[60];
02565     unsigned int w = (ramptime * 1000)/ 256;
02566     int delay = 200;
02567 
02568     if (!SuppressSlowStuff)
02569         pc.printf("Backlight Test - ramp over %f sec.\r\n", ramptime);
02570     else {
02571         delay = 0;
02572         w = 0;
02573     }
02574     display.Backlight_u8(0);
02575     display.background(White);
02576     display.foreground(Blue);
02577     display.cls();
02578     display.puts("RA8875 Backlight Test - Ramp up.");
02579     wait_ms(delay);
02580     for (int i=0; i <= 255; i++) {
02581         snprintf(buf, sizeof(buf), "%3d, %4d", i, w);
02582         display.puts(100,100,buf);
02583         display.Backlight_u8(i);
02584         wait_ms(w);
02585     }
02586 }
02587 
02588 
02589 void BacklightTest2(RA8875 & display, Serial & pc)
02590 {
02591     int delay = 20;
02592 
02593     if (!SuppressSlowStuff)
02594         pc.printf("Backlight Test 2\r\n");
02595     else
02596         delay = 0;
02597 
02598     // Dim it out at the end of the tests.
02599     display.foreground(Blue);
02600     display.puts(0,0, "Ramp Backlight down.");
02601     // Ramp it off
02602     for (int i=255; i != 0; i--) {
02603         display.Backlight_u8(i);
02604         wait_ms(delay);
02605     }
02606     display.Backlight_u8(0);
02607 }
02608 
02609 
02610 void ExternalFontTest(RA8875 & display, Serial & pc)
02611 {
02612     if (!SuppressSlowStuff)
02613         pc.printf("External Font Test\r\n");
02614     display.background(Black);
02615     display.foreground(Blue);
02616     display.cls();
02617     display.puts("External Font Test.");
02618     display.Backlight(1);
02619 
02620     display.SelectUserFont(BPG_Arial08x08);
02621     display.puts(0,30, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\r\n");
02622 
02623     display.SelectUserFont(BPG_Arial20x20);
02624     display.puts("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\r\n");
02625     
02626     display.SelectUserFont();
02627 
02628     display.puts("Normal font again.");
02629     //display.window(0,0, display.width(), display.height());
02630 }
02631 
02632 
02633 void DOSColorTest(RA8875 & display, Serial & pc)
02634 {
02635     if (!SuppressSlowStuff)
02636         pc.printf("DOS Color Test\r\n");
02637     display.background(Black);
02638     display.foreground(Blue);
02639     display.cls();
02640     display.puts("DOS Colors - Fore");
02641     display.puts(280,0, "Back");
02642     display.background(Gray);
02643     for (int i=0; i<16; i++) {
02644         display.foreground(display.DOSColor(i));
02645         display.puts(160, i*16, display.DOSColorNames(i));
02646         display.background(Black);
02647     }
02648     display.foreground(White);
02649     for (int i=0; i<16; i++) {
02650         display.background(display.DOSColor(i));
02651         display.puts(360, i*16, display.DOSColorNames(i));
02652         display.foreground(White);
02653     }
02654 }
02655 
02656 
02657 void WebColorTest(RA8875 & display, Serial & pc)
02658 {
02659     if (!SuppressSlowStuff)
02660         pc.printf("Web Color Test\r\n");
02661     display.background(Black);
02662     display.foreground(Blue);
02663     display.window(0,0, display.width(), display.height());
02664     display.cls();
02665     display.SetTextFontSize(1,1);
02666     display.puts(200,0, "Web Color Test");
02667     display.SetTextCursor(0,0);
02668     display.puts("  ");
02669     for (int i=0; i<16; i++)
02670         display.printf("%X", i&0xF);
02671     display.puts("\r\n0 ");
02672     for (int i=0; i<sizeof(WebColors)/sizeof(WebColors[0]); i++) {
02673         display.background(WebColors[i]);
02674         display.puts(" ");
02675         if (i % 16 == 15 && i < 255) {
02676             display.printf("\r\n%X ", ((i+1)/16));
02677         }
02678     }
02679     display.SetTextFontSize(1,1);
02680 }
02681 
02682 
02683 void PixelTest(RA8875 & display, Serial & pc)
02684 {
02685     int i, c, x, y;
02686 
02687     if (!SuppressSlowStuff)
02688         pc.printf("Pixel Test\r\n");
02689     display.background(Black);
02690     display.foreground(Blue);
02691     display.cls();
02692     display.puts("Pixel Test");
02693     for (i=0; i<1000; i++) {
02694         x = rand() % 480;
02695         y = 16 + rand() % (272-16);
02696         c = rand() % 16;
02697         //pc.printf("  (%d,%d) - %d\r\n", x,y,r1);
02698         display.pixel(x,y, display.DOSColor(c));
02699     }
02700 }
02701 
02702 
02703 void LineTest(RA8875 & display, Serial & pc)
02704 {
02705     int i, x, y, x2, y2;
02706 
02707     if (!SuppressSlowStuff)
02708         pc.printf("Line Test\r\n");
02709     display.background(Black);
02710     display.foreground(Blue);
02711     display.cls();
02712     display.puts("Line Test");
02713     for (i=0; i<16; i++) {
02714         // Lines
02715         x = rand() % 480;
02716         y = rand() % 272;
02717         x2 = rand() % 480;
02718         y2 = rand() % 272;
02719         display.line(x,y, x2,y2, display.DOSColor(i));
02720     }
02721     display.foreground(BrightRed);
02722     display.foreground(BrightGreen);
02723     display.foreground(BrightBlue);
02724     display.line(55,50, 79,74, BrightRed);
02725     display.line(57,50, 81,74, BrightGreen);
02726     display.line(59,50, 83,74, BrightBlue);
02727     // horz
02728     display.line(30,40, 32,40, BrightRed);
02729     display.line(30,42, 32,42, BrightGreen);
02730     display.line(30,44, 32,44, BrightBlue);
02731     // vert
02732     display.line(20,40, 20,42, BrightRed);
02733     display.line(22,40, 22,42, BrightGreen);
02734     display.line(24,40, 24,42, BrightBlue);
02735     // compare point to line-point
02736     display.pixel(20,50, BrightRed);
02737     display.pixel(22,50, BrightGreen);
02738     display.pixel(24,50, BrightBlue);
02739     display.line(20,52, 20,52, BrightRed);
02740     display.line(22,52, 22,52, BrightGreen);
02741     display.line(24,52, 24,52, BrightBlue);
02742 
02743     // point
02744     display.line(50,50, 50,50, Red);
02745     display.line(52,52, 52,52, Green);
02746     display.line(54,54, 54,54, Blue);
02747     display.line(60,60, 60,60, BrightRed);
02748     display.line(62,62, 62,62, BrightGreen);
02749     display.line(64,64, 64,64, BrightBlue);
02750     display.line(70,70, 70,70, DarkRed);
02751     display.line(72,72, 72,72, DarkGreen);
02752     display.line(74,74, 74,74, DarkBlue);
02753 }
02754 
02755 
02756 void RectangleTest(RA8875 & display, Serial & pc)
02757 {
02758     int i, x1,y1, x2,y2;
02759 
02760     if (!SuppressSlowStuff)
02761         pc.printf("Rectangle Test\r\n");
02762     display.background(Black);
02763     display.foreground(Blue);
02764     display.cls();
02765     display.puts("Rectangle Test");
02766     for (i=0; i<16; i++) {
02767         x1 = rand() % 240;
02768         y1 = 50 + rand() % 200;
02769         x2 = rand() % 240;
02770         y2 = 50 + rand() % 200;
02771         display.rect(x1,y1, x2,y2, display.DOSColor(i));
02772 
02773         x1 = 240 + rand() % 240;
02774         y1 = 50 + rand() % 200;
02775         x2 = 240 + rand() % 240;
02776         y2 = 50 + rand() % 200;
02777         display.rect(x1,y1, x2,y2, FILL);
02778     }
02779 }
02780 
02781 
02782 void LayerTest(RA8875 & display, Serial & pc)
02783 {
02784     loc_t i, x1,y1, x2,y2, r1,r2;
02785 
02786     if (!SuppressSlowStuff)
02787         pc.printf("Layer Test\r\n");
02788 
02789     display.SelectDrawingLayer(0);
02790     display.background(Black);
02791     display.foreground(Blue);
02792     display.cls();
02793     display.puts("Layer 0");
02794     for (i=0; i<16; i++) {
02795         x1 = rand() % 240;
02796         y1 = 50 + rand() % 200;
02797         x2 = x1 + rand() % 100;
02798         y2 = y1 + rand() % 100;
02799         r1 = rand() % (x2 - x1)/2;
02800         r2 = rand() % (y2 - y1)/2;
02801         display.roundrect(x1,y1, x2,y2, r1,r2, display.DOSColor(i));
02802         if (!SuppressSlowStuff)
02803             wait_ms(20);
02804     }
02805     if (!SuppressSlowStuff)
02806         wait_ms(1000);
02807 
02808     display.SelectDrawingLayer(1);
02809     display.background(Black);
02810     display.foreground(Yellow);
02811     display.cls();
02812     display.puts(240,0, "Layer 1");
02813     for (i=0; i<16; i++) {
02814         x1 = 300 + rand() % 100;
02815         y1 = 70 + rand() % 200;
02816         r1 = rand() % min(y1 - 20, 100);
02817         display.circle(x1,y1,r1, display.DOSColor(i));
02818         if (!SuppressSlowStuff)
02819             wait_ms(20);
02820     }
02821     display.SetLayerMode(RA8875::ShowLayer1);        // Show it after the build-up
02822     if (!SuppressSlowStuff)
02823         wait_ms(2000);
02824 
02825     display.SelectDrawingLayer(0);
02826     display.SetLayerMode(RA8875::ShowLayer0);        // Show Layer 0 again
02827     if (!SuppressSlowStuff)
02828         wait_ms(1000);
02829     display.SetLayerMode(RA8875::TransparentMode);        // Transparent mode
02830     if (!SuppressSlowStuff)
02831         wait_ms(1000);
02832     for (i=0; i<=8; i++) {
02833         display.SetLayerTransparency(i, 8-i);
02834         if (!SuppressSlowStuff)
02835             wait_ms(200);
02836     }
02837 
02838     // Restore before we exit
02839     display.SetLayerTransparency(0, 0);
02840     display.SetLayerMode(RA8875::ShowLayer0);        // Restore to layer 0
02841 }
02842 
02843 
02844 void RoundRectTest(RA8875 & display, Serial & pc)
02845 {
02846     loc_t i, x1,y1, x2,y2, r1,r2;
02847 
02848     if (!SuppressSlowStuff)
02849         pc.printf("Round Rectangle Test\r\n");
02850     display.background(Black);
02851     display.foreground(Blue);
02852     display.cls();
02853     display.puts("Rounded Rectangle Test");
02854 
02855     for (i=0; i<16; i++) {
02856         x1 = rand() % 240;
02857         y1 = 50 + rand() % 200;
02858         x2 = x1 + rand() % 100;
02859         y2 = y1 + rand() % 100;
02860         r1 = rand() % (x2 - x1)/2;
02861         r2 = rand() % (y2 - y1)/2;
02862         display.roundrect(x1,y1, x2,y2, 5,8, display.DOSColor(i));
02863 
02864         x1 = 240 + rand() % 240;
02865         y1 = 50 + rand() % 200;
02866         x2 = x1 + rand() % 100;
02867         y2 = y1 + rand() % 100;
02868         r1 = rand() % (x2 - x1)/2;
02869         r2 = rand() % (y2 - y1)/2;
02870         display.roundrect(x1,y1, x2,y2, r1,r2, FILL);
02871     }
02872 }
02873 
02874 
02875 void TriangleTest(RA8875 & display, Serial & pc)
02876 {
02877     int i, x1, y1, x2, y2, x3, y3;
02878 
02879     if (!SuppressSlowStuff)
02880         pc.printf("Triangle Test\r\n");
02881     display.background(Black);
02882     display.foreground(Blue);
02883     display.cls();
02884     display.puts(0,0, "Triangle Test");
02885 
02886     x1 = 150;
02887     y1 = 2;
02888     x2 = 190;
02889     y2 = 7;
02890     x3 = 170;
02891     y3 = 16;
02892     display.triangle(x1,y1, x2,y2, x3,y3);
02893 
02894     x1 = 200;
02895     y1 = 2;
02896     x2 = 240;
02897     y2 = 7;
02898     x3 = 220;
02899     y3 = 16;
02900     display.filltriangle(x1,y1, x2,y2, x3,y3, BrightRed);
02901 
02902     x1 = 300;
02903     y1 = 2;
02904     x2 = 340;
02905     y2 = 7;
02906     x3 = 320;
02907     y3 = 16;
02908     display.triangle(x1,y1, x2,y2, x3,y3, NOFILL);
02909 
02910     x1 = 400;
02911     y1 = 2;
02912     x2 = 440;
02913     y2 = 7;
02914     x3 = 420;
02915     y3 = 16;
02916     display.triangle(x1,y1, x2,y2, x3,y3, Blue);
02917 
02918     for (i=0; i<16; i++) {
02919         x1 = rand() % 240;
02920         y1 = 50 + rand() % 200;
02921         x2 = rand() % 240;
02922         y2 = 50 + rand() % 200;
02923         x3 = rand() % 240;
02924         y3 = 50 + rand() % 200;
02925         display.triangle(x1,y1, x2,y2, x3,y3, display.DOSColor(i));
02926         x1 = 240 + rand() % 240;
02927         y1 = 50 + rand() % 200;
02928         x2 = 240 + rand() % 240;
02929         y2 = 50 + rand() % 200;
02930         x3 = 240 + rand() % 240;
02931         y3 = 50 + rand() % 200;
02932         display.triangle(x1,y1, x2,y2, x3,y3, FILL);
02933     }
02934 }
02935 
02936 
02937 void CircleTest(RA8875 & display, Serial & pc)
02938 {
02939     int i, x, y, r1;
02940 
02941     if (!SuppressSlowStuff)
02942         pc.printf("Circle Test\r\n");
02943     display.background(Black);
02944     display.foreground(Blue);
02945     display.cls();
02946     display.puts("Circle Test");
02947     for (i=0; i<16; i++) {
02948         x = 100 + rand() % 100;
02949         y = 70 + rand() % 200;
02950         r1 = rand() % min(y - 20, 100);
02951         //pc.printf("  (%d,%d) - %d\r\n", x,y,r1);
02952         display.circle(x,y,r1, display.DOSColor(i));
02953 
02954         x = 300 + rand() % 100;
02955         y = 70 + rand() % 200;
02956         r1 = rand() % min(y - 20, 100);
02957         //pc.printf("  (%d,%d) - %d FILL\r\n", x,y,r1);
02958         display.circle(x,y,r1, display.DOSColor(i), FILL);
02959     }
02960 }
02961 
02962 
02963 void EllipseTest(RA8875 & display, Serial & pc)
02964 {
02965     int i,x,y,r1,r2;
02966 
02967     if (!SuppressSlowStuff)
02968         pc.printf("Ellipse Test\r\n");
02969     display.background(Black);
02970     display.foreground(Blue);
02971     display.cls();
02972     display.puts("Ellipse Test");
02973     for (i=0; i<16; i++) {
02974         x = 100 + rand() % 100;
02975         y = 70 + rand() % 200;
02976         r1 = rand() % min(y - 20, 100);
02977         r2 = rand() % min(y - 20, 100);
02978         display.ellipse(x,y,r1,r2, display.DOSColor(i));
02979 
02980         x = 300 + rand() % 100;
02981         y = 70 + rand() % 200;
02982         r1 = rand() % min(y - 20, 100);
02983         r2 = rand() % min(y - 20, 100);
02984         display.ellipse(x,y,r1,r2, FILL);
02985     }
02986 }
02987 
02988 
02989 void TestGraphicsBitmap(RA8875 & display, Serial & pc)
02990 {
02991     LocalFileSystem local("local");
02992     if (!SuppressSlowStuff)
02993         pc.printf("Bitmap File Load\r\n");
02994     display.background(Black);
02995     display.foreground(Blue);
02996     display.cls();
02997     display.puts("Graphics Test, loading /local/TestPat.bmp");
02998     wait(3);
02999 
03000     int r = display.RenderBitmapFile(0,0, "/local/TestPat.bmp");
03001     if (!SuppressSlowStuff)
03002         pc.printf("  returned %d\r\n", r);
03003 }
03004 
03005 
03006 void TouchPanelTest(RA8875 & display, Serial & pc)
03007 {
03008     Timer t;
03009     int x, y;
03010     tpMatrix_t calmatrix;
03011     
03012     display.background(Black);
03013     display.foreground(Blue);
03014     display.cls();
03015     display.puts("Touch Panel Test\r\n");
03016     pc.printf("Touch Panel Test\r\n");
03017     display.TouchPanelInit();
03018     pc.printf("  TP: c - calibrate, r - restore, t - test\r\n");
03019     int c = pc.getc();
03020     if (c == 'c') {
03021         point_t pTest[3] =
03022         { { 50, 50 }, {450, 150}, {225,250} };
03023         point_t pSample[3];
03024         for (int i=0; i<3; i++) {
03025             display.foreground(Blue);
03026             display.printf(" (%3d,%3d) => ", pTest[i].x, pTest[i].y);
03027             display.line(pTest[i].x-10, pTest[i].y, pTest[i].x+10, pTest[i].y, White);
03028             display.line(pTest[i].x, pTest[i].y-10, pTest[i].x, pTest[i].y+10, White);
03029             while (!display.TouchPanelA2DFiltered(&x, &y))
03030                 wait_ms(20);
03031             pSample[i].x = x;
03032             pSample[i].y = y;
03033             display.line(pTest[i].x-10, pTest[i].y, pTest[i].x+10, pTest[i].y, Black);
03034             display.line(pTest[i].x, pTest[i].y-10, pTest[i].x, pTest[i].y+10, Black);
03035             display.foreground(Blue);
03036             display.printf(" (%4d,%4d)\r\n", x,y);
03037             while (display.TouchPanelA2DFiltered(&x, &y))
03038                 wait_ms(20);
03039             wait(2);
03040         }
03041         display.TouchPanelComputeCalibration(pTest, pSample, &calmatrix);
03042         display.printf(" Writing calibration to tpcal.cfg\r\n");
03043         FILE * fh = fopen("/local/tpcal.cfg", "wb");
03044         if (fh) {
03045             fwrite(&calmatrix, sizeof(calmatrix), 1, fh);
03046             fclose(fh);
03047         }
03048         display.printf(" Calibration is complete.");
03049     } else if (c == 'r') {
03050         display.printf(" Reading calibration from tpcal.cfg\r\n");
03051         FILE * fh = fopen("/local/tpcal.cfg", "rb");
03052         if (fh) {
03053             fread(&calmatrix, sizeof(calmatrix), 1, fh);
03054             fclose(fh);
03055         }
03056         display.printf(" Calibration is complete.");
03057         display.TouchPanelSetMatrix(&calmatrix);
03058     }
03059     t.start();
03060     do {
03061         point_t point = {0, 0};
03062         if (display.TouchPanelReadable(&point)) {
03063             display.pixel(point.x, point.y, Red);
03064         }
03065     } while (t.read_ms() < 30000);
03066     pc.printf(">");
03067 }
03068 
03069 
03070 void SpeedTest(RA8875 & display, Serial & pc)
03071 {
03072     Timer t;
03073     SuppressSlowStuff = true;
03074     pc.printf("\r\nSpeedTest disables delays, runs tests, reports overall time.\r\n");
03075     t.start();
03076     // do stuff fast
03077     TextCursorTest(display, pc);
03078     TextWrapTest(display, pc);
03079     BacklightTest(display, pc, 0);
03080     BacklightTest2(display, pc);
03081     ExternalFontTest(display, pc);
03082     DOSColorTest(display, pc);
03083     WebColorTest(display, pc);
03084     PixelTest(display, pc);
03085     LineTest(display, pc);
03086     RectangleTest(display, pc);
03087     RoundRectTest(display, pc);
03088     TriangleTest(display, pc);
03089     CircleTest(display, pc);
03090     EllipseTest(display, pc);
03091     LayerTest(display, pc);
03092     //TestGraphicsBitmap(display, pc);
03093     pc.printf("SpeedTest completed in %d msec\r\n", t.read_ms());
03094 #ifdef PERF_METRICS
03095     display.ReportPerformance(pc);
03096 #endif
03097     SuppressSlowStuff = false;
03098 }
03099 
03100 
03101 void PrintScreen(RA8875 & display, Serial & pc)
03102 {
03103     if (!SuppressSlowStuff)
03104         pc.printf("PrintScreen\r\n");
03105     display.PrintScreen( 0,0, 480,272, "/local/Capture.bmp");
03106 }
03107 
03108 
03109 void RunTestSet(RA8875 & lcd, Serial & pc)
03110 {
03111     int q = 0;
03112     int automode = 0;
03113     const unsigned char modelist[] = "BDWtGLlFROTPCEbw";   // auto-test in this order.
03114 
03115     while(1) {
03116         pc.printf("\r\n"
03117                   "B - Backlight up      b - backlight dim\r\n"
03118                   "D - DOS Colors        W - Web Colors\r\n"
03119                   "t - text cursor       G - Graphics Bitmap\r\n"
03120                   "L - Lines             F - external Font\r\n"
03121                   "R - Rectangles        O - rOund rectangles\r\n"
03122                   "T - Triangles         P - Pixels  \r\n"
03123                   "C - Circles           E - Ellipses\r\n"
03124                   "A - Auto Test mode    S - Speed Test\r\n"
03125                   "K - Keypad Test       s - touch screen test\r\n"
03126                   "p - print screen      r - reset  \r\n"
03127                   "l - layer test        w - wrapping text \r\n"
03128 #ifdef PERF_METRICS
03129                   "0 - clear performance 1 - report performance\r\n"
03130 #endif
03131                   "> ");
03132         if (automode == -1 || pc.readable()) {
03133             automode = -1;
03134             q = pc.getc();
03135             while (pc.readable())
03136                 pc.getc();
03137         } else if (automode >= 0) {
03138             q = modelist[automode];
03139         }
03140         switch(q) {
03141 #ifdef PERF_METRICS
03142             case '0':
03143                 lcd.ClearPerformance();
03144                 break;
03145             case '1':
03146                 lcd.ReportPerformance(pc);
03147                 break;
03148 #endif
03149             case 'A':
03150                 automode = 0;
03151                 break;
03152             case 'B':
03153                 BacklightTest(lcd, pc, 2);
03154                 break;
03155             case 'b':
03156                 BacklightTest2(lcd, pc);
03157                 break;
03158             case 'D':
03159                 DOSColorTest(lcd, pc);
03160                 break;
03161             case 'K':
03162                 KeyPadTest(lcd, pc);
03163                 break;
03164             case 'W':
03165                 WebColorTest(lcd, pc);
03166                 break;
03167             case 't':
03168                 TextCursorTest(lcd, pc);
03169                 break;
03170             case 'w':
03171                 TextWrapTest(lcd, pc);
03172                 break;
03173             case 'F':
03174                 ExternalFontTest(lcd, pc);
03175                 break;
03176             case 'L':
03177                 LineTest(lcd, pc);
03178                 break;
03179             case 'l':
03180                 LayerTest(lcd, pc);
03181                 break;
03182             case 'R':
03183                 RectangleTest(lcd, pc);
03184                 break;
03185             case 'O':
03186                 RoundRectTest(lcd, pc);
03187                 break;
03188             case 'p':
03189                 PrintScreen(lcd, pc);
03190                 break;
03191             case 'S':
03192                 SpeedTest(lcd, pc);
03193                 break;
03194             case 's':
03195                 TouchPanelTest(lcd, pc);
03196                 break;
03197             case 'T':
03198                 TriangleTest(lcd, pc);
03199                 break;
03200             case 'P':
03201                 PixelTest(lcd, pc);
03202                 break;
03203             case 'G':
03204                 TestGraphicsBitmap(lcd, pc);
03205                 break;
03206             case 'C':
03207                 CircleTest(lcd, pc);
03208                 break;
03209             case 'E':
03210                 EllipseTest(lcd, pc);
03211                 break;
03212             case 'r':
03213                 pc.printf("Resetting ...\r\n");
03214                 wait_ms(20);
03215                 mbed_reset();
03216                 break;
03217             case ' ':
03218                 break;
03219             default:
03220                 printf("huh?\n");
03221                 break;
03222         }
03223         if (automode >= 0) {
03224             automode++;
03225             if (automode >= sizeof(modelist))
03226                 automode = 0;
03227             wait_ms(2000);
03228         }
03229         wait_ms(200);
03230     }
03231 }
03232 
03233 #endif // TESTENABLE