CUER / RA8875

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)) {
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)) {
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)) {
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     _spiwrite(0x00);         // Cmd: write data
01319     while (h--) {
01320         uint8_t pixels = w;
01321         uint8_t bitmask = 0x01;
01322         
01323         while (pixels) {
01324             uint8_t byte = *boolStream;
01325             //INFO("byte, mask: %02X, %02X", byte, bitmask);
01326             color_t c = (byte & bitmask) ? _foreground : _background;
01327                 if (screenbpp == 16) {
01328                     _spiwrite(c >> 8);
01329                     _spiwrite(c & 0xFF);
01330                 } else {
01331                     _spiwrite(_cvt16to8(c));
01332                 }
01333             bitmask <<= 1;
01334             if (pixels > 1 && bitmask == 0) {
01335                 bitmask = 0x01;
01336                 boolStream++;
01337             }
01338             pixels--;
01339         }
01340         boolStream++;
01341     }
01342     _select(false);
01343     _EndGraphicsStream();
01344     window(restore);
01345     REGISTERPERFORMANCE(PRF_BOOLSTREAM);
01346     return(noerror);
01347 }
01348 
01349 color_t RA8875::getPixel(loc_t x, loc_t y)
01350 {
01351     color_t pixel;
01352 
01353     PERFORMANCE_RESET;
01354     WriteCommand(0x40,0x00);    // Graphics write mode
01355     SetGraphicsCursorRead(x, y);
01356     WriteCommand(0x02);
01357     _select(true);
01358     _spiwrite(0x40);         // Cmd: read data
01359     _spiwrite(0x00);         // dummy read
01360     if (screenbpp == 16) {
01361         pixel  = _spiread();
01362         pixel |= (_spiread() << 8);
01363     } else {
01364         pixel = _cvt8to16(_spiread());
01365     }
01366     _select(false);
01367     REGISTERPERFORMANCE(PRF_READPIXEL);
01368     return pixel;
01369 }
01370 
01371 
01372 RetCode_t RA8875::getPixelStream(color_t * p, uint32_t count, loc_t x, loc_t y)
01373 {
01374     color_t pixel;
01375     RetCode_t ret = noerror;
01376 
01377     PERFORMANCE_RESET;
01378     ret = WriteCommand(0x40,0x00);    // Graphics write mode
01379     ret = SetGraphicsCursorRead(x, y);
01380     ret = WriteCommand(0x02);
01381     _select(true);
01382     _spiwrite(0x40);         // Cmd: read data
01383     _spiwrite(0x00);         // dummy read
01384     if (screenbpp == 16)
01385         _spiwrite(0x00);     // dummy read is only necessary when in 16-bit mode
01386     while (count--) {
01387         if (screenbpp == 16) {
01388             pixel  = _spiread();
01389             pixel |= (_spiread() << 8);
01390         } else {
01391             pixel = _cvt8to16(_spiread());
01392         }
01393         *p++ = pixel;
01394     }
01395     _select(false);
01396     REGISTERPERFORMANCE(PRF_READPIXELSTREAM);
01397     return ret;
01398 }
01399 
01400 
01401 RetCode_t RA8875::line(point_t p1, point_t p2)
01402 {
01403     return line(p1.x, p1.y, p2.x, p2.y);
01404 }
01405 
01406 
01407 RetCode_t RA8875::line(point_t p1, point_t p2, color_t color)
01408 {
01409     return line(p1.x, p1.y, p2.x, p2.y, color);
01410 }
01411 
01412 
01413 RetCode_t RA8875::line(loc_t x1, loc_t y1, loc_t x2, loc_t y2, color_t color)
01414 {
01415     foreground(color);
01416     return line(x1,y1,x2,y2);
01417 }
01418 
01419 
01420 RetCode_t RA8875::line(loc_t x1, loc_t y1, loc_t x2, loc_t y2)
01421 {
01422     PERFORMANCE_RESET;
01423     if (x1 == x2 && y1 == y2) {
01424         pixel(x1, y1);
01425     } else {
01426         WriteCommandW(0x91, x1);
01427         WriteCommandW(0x93, y1);
01428         WriteCommandW(0x95, x2);
01429         WriteCommandW(0x97, y2);
01430         unsigned char drawCmd = 0x00;       // Line
01431         WriteCommand(0x90, drawCmd);
01432         WriteCommand(0x90, 0x80 + drawCmd); // Start drawing.
01433         if (!_WaitWhileReg(0x90, 0x80)) {
01434             REGISTERPERFORMANCE(PRF_DRAWLINE);
01435             return external_abort;
01436         }
01437     }
01438     REGISTERPERFORMANCE(PRF_DRAWLINE);
01439     return noerror;
01440 }
01441 
01442 
01443 RetCode_t RA8875::ThickLine(point_t p1, point_t p2, dim_t thickness, color_t color)
01444 {
01445     if (thickness == 1) {
01446         line(p1,p2, color);
01447     } else {
01448         int dx = abs(p2.x-p1.x), sx = p1.x<p2.x ? 1 : -1;
01449         int dy = abs(p2.y-p1.y), sy = p1.y<p2.y ? 1 : -1;
01450         int err = (dx>dy ? dx : -dy)/2, e2;
01451         
01452         for (;;) {
01453             fillcircle(p1.x, p1.y, thickness/2, color);
01454             if (p1.x==p2.x && p1.y==p2.y) 
01455                 break;
01456             e2 = err;
01457             if (e2 >-dx) 
01458                 { err -= dy; p1.x += sx; }
01459             if (e2 < dy) 
01460                 { err += dx; p1.y += sy; }
01461         }        
01462     }
01463     return noerror;
01464 }
01465 
01466 
01467 //
01468 // Rectangle functions all mostly helpers to the basic rectangle function
01469 //
01470 
01471 RetCode_t RA8875::fillrect(rect_t r, color_t color, fill_t fillit)
01472 {
01473     return rect(r.p1.x, r.p1.y, r.p2.x, r.p2.y, color, fillit);
01474 }
01475 
01476 RetCode_t RA8875::fillrect(loc_t x1, loc_t y1, loc_t x2, loc_t y2,
01477                            color_t color, fill_t fillit)
01478 {
01479     return rect(x1,y1,x2,y2,color,fillit);
01480 }
01481 
01482 RetCode_t RA8875::rect(rect_t r, color_t color, fill_t fillit)
01483 {
01484     return rect(r.p1.x, r.p1.y, r.p2.x, r.p2.y, color, fillit);
01485 }
01486 
01487 RetCode_t RA8875::rect(loc_t x1, loc_t y1, loc_t x2, loc_t y2,
01488                        color_t color, fill_t fillit)
01489 {
01490     foreground(color);
01491     return rect(x1,y1,x2,y2,fillit);
01492 }
01493 
01494 RetCode_t RA8875::rect(loc_t x1, loc_t y1, loc_t x2, loc_t y2,
01495                        fill_t fillit)
01496 {
01497     RetCode_t ret = noerror;
01498     PERFORMANCE_RESET;
01499     // check for bad_parameter
01500     if (x1 < 0 || x1 >= screenwidth || x2 < 0 || x2 >= screenwidth 
01501     || y1 < 0 || y1 >= screenheight || y2 < 0 || y2 >= screenheight) {
01502         ret = bad_parameter;
01503     } else {
01504         if (x1 == x2 && y1 == y2) {
01505             pixel(x1, y1);
01506         } else if (x1 == x2) {
01507             line(x1, y1, x2, y2);
01508         } else if (y1 == y2) {
01509             line(x1, y1, x2, y2);
01510         } else {
01511             WriteCommandW(0x91, x1);
01512             WriteCommandW(0x93, y1);
01513             WriteCommandW(0x95, x2);
01514             WriteCommandW(0x97, y2);
01515             unsigned char drawCmd = 0x10;   // Rectangle
01516             if (fillit == FILL)
01517                 drawCmd |= 0x20;
01518             WriteCommand(0x90, drawCmd);
01519             ret = WriteCommand(0x90, 0x80 + drawCmd); // Start drawing.
01520             if (!_WaitWhileReg(0x90, 0x80)) {
01521                 REGISTERPERFORMANCE(PRF_DRAWRECTANGLE);
01522                 return external_abort;
01523             }
01524         }
01525     }
01526     REGISTERPERFORMANCE(PRF_DRAWRECTANGLE);
01527     return ret;
01528 }
01529 
01530 
01531 //
01532 // rounded rectangle functions are mostly helpers to the base round rect
01533 //
01534 
01535 RetCode_t RA8875::fillroundrect(rect_t r, dim_t radius1, dim_t radius2, color_t color, fill_t fillit)
01536 {
01537     return roundrect(r.p1.x, r.p1.y, r.p2.x, r.p2.y, radius1, radius2, color, fillit);
01538 }
01539 
01540 RetCode_t RA8875::fillroundrect(loc_t x1, loc_t y1, loc_t x2, loc_t y2,
01541                                 dim_t radius1, dim_t radius2, color_t color, fill_t fillit)
01542 {
01543     foreground(color);
01544     return roundrect(x1,y1,x2,y2,radius1,radius2,fillit);
01545 }
01546 
01547 RetCode_t RA8875::roundrect(rect_t r, dim_t radius1, dim_t radius2, color_t color, fill_t fillit)
01548 {
01549     return roundrect(r.p1.x, r.p1.y, r.p2.x, r.p2.y, radius1, radius2, color, fillit);
01550 }
01551 
01552 RetCode_t RA8875::roundrect(loc_t x1, loc_t y1, loc_t x2, loc_t y2,
01553                             dim_t radius1, dim_t radius2, color_t color, fill_t fillit)
01554 {
01555     foreground(color);
01556     return roundrect(x1,y1,x2,y2,radius1,radius2,fillit);
01557 }
01558 
01559 
01560 RetCode_t RA8875::roundrect(loc_t x1, loc_t y1, loc_t x2, loc_t y2,
01561                             dim_t radius1, dim_t radius2, fill_t fillit)
01562 {
01563     RetCode_t ret = noerror;
01564 
01565     PERFORMANCE_RESET;
01566     if (x1 < 0 || x1 >= screenwidth || x2 < 0 || x2 >= screenwidth 
01567     || y1 < 0 || y1 >= screenheight || y2 < 0 || y2 >= screenheight) {
01568         ret = bad_parameter;
01569     } else if (x1 > x2 || y1 > y2 || (radius1 > (x2-x1)/2) || (radius2 > (y2-y1)/2) ) {
01570         ret = bad_parameter;
01571     } else if (x1 == x2 && y1 == y2) {
01572         pixel(x1, y1);
01573     } else if (x1 == x2) {
01574         line(x1, y1, x2, y2);
01575     } else if (y1 == y2) {
01576         line(x1, y1, x2, y2);
01577     } else {
01578         WriteCommandW(0x91, x1);
01579         WriteCommandW(0x93, y1);
01580         WriteCommandW(0x95, x2);
01581         WriteCommandW(0x97, y2);
01582         WriteCommandW(0xA1, radius1);
01583         WriteCommandW(0xA3, radius2);
01584         // Should not need this...
01585         WriteCommandW(0xA5, 0);
01586         WriteCommandW(0xA7, 0);
01587         unsigned char drawCmd = 0x20;       // Rounded Rectangle
01588         if (fillit == FILL)
01589             drawCmd |= 0x40;
01590         WriteCommand(0xA0, drawCmd);
01591         WriteCommand(0xA0, 0x80 + drawCmd); // Start drawing.
01592         if (!_WaitWhileReg(0xA0, 0x80)) {
01593             REGISTERPERFORMANCE(PRF_DRAWROUNDEDRECTANGLE);
01594             return external_abort;
01595         }
01596     }
01597     REGISTERPERFORMANCE(PRF_DRAWROUNDEDRECTANGLE);
01598     return ret;
01599 }
01600 
01601 
01602 //
01603 // triangle functions
01604 //
01605 
01606 RetCode_t RA8875::triangle(loc_t x1, loc_t y1, loc_t x2, loc_t y2,
01607                            loc_t x3, loc_t y3, color_t color, fill_t fillit)
01608 {
01609     RetCode_t ret;
01610 
01611     if (x1 < 0 || x1 >= screenwidth || x2 < 0 || x2 >= screenwidth || x3 < 0 || x3 >= screenwidth
01612     || y1 < 0 || y1 >= screenheight || y2 < 0 || y2 >= screenheight || y3 < 0 || y3 >= screenheight)
01613         ret = bad_parameter;
01614     foreground(color);
01615     ret = triangle(x1,y1,x2,y2,x3,y3,fillit);
01616     return ret;
01617 }
01618 
01619 
01620 RetCode_t RA8875::filltriangle(loc_t x1, loc_t y1, loc_t x2, loc_t y2,
01621                                loc_t x3, loc_t y3, color_t color, fill_t fillit)
01622 {
01623     RetCode_t ret;
01624 
01625     foreground(color);
01626     ret = triangle(x1,y1,x2,y2,x3,y3,fillit);
01627     return ret;
01628 }
01629 
01630 
01631 RetCode_t RA8875::triangle(loc_t x1, loc_t y1 ,loc_t x2, loc_t y2,
01632                            loc_t x3, loc_t y3, fill_t fillit)
01633 {
01634     RetCode_t ret = noerror;
01635 
01636     PERFORMANCE_RESET;
01637     if (x1 == x2 && y1 == y2 && x1 == x3 && y1 == y3) {
01638         pixel(x1, y1);
01639     } else {
01640         WriteCommandW(0x91, x1);
01641         WriteCommandW(0x93, y1);
01642         WriteCommandW(0x95, x2);
01643         WriteCommandW(0x97, y2);
01644         WriteCommandW(0xA9, x3);
01645         WriteCommandW(0xAB, y3);
01646         unsigned char drawCmd = 0x01;       // Triangle
01647         if (fillit == FILL)
01648             drawCmd |= 0x20;
01649         WriteCommand(0x90, drawCmd);
01650         WriteCommand(0x90, 0x80 + drawCmd); // Start drawing.
01651         if (!_WaitWhileReg(0x90, 0x80)) {
01652             REGISTERPERFORMANCE(PRF_DRAWTRIANGLE);
01653             return external_abort;
01654         }
01655     }
01656     REGISTERPERFORMANCE(PRF_DRAWTRIANGLE);
01657     return ret;
01658 }
01659 
01660 
01661 RetCode_t RA8875::circle(point_t p, dim_t radius,
01662                          color_t color, fill_t fillit)
01663 {
01664     foreground(color);
01665     return circle(p.x,p.y,radius,fillit);
01666 }
01667 
01668 
01669 RetCode_t RA8875::fillcircle(point_t p, dim_t radius,
01670                              color_t color, fill_t fillit)
01671 {
01672     foreground(color);
01673     return circle(p.x,p.y,radius,fillit);
01674 }
01675 
01676 
01677 RetCode_t RA8875::circle(point_t p, dim_t radius, fill_t fillit)
01678 {
01679     return circle(p.x,p.y,radius,fillit);
01680 }
01681 
01682 
01683 RetCode_t RA8875::circle(loc_t x, loc_t y, dim_t radius,
01684                          color_t color, fill_t fillit)
01685 {
01686     foreground(color);
01687     return circle(x,y,radius,fillit);
01688 }
01689 
01690 
01691 RetCode_t RA8875::fillcircle(loc_t x, loc_t y, dim_t radius,
01692                              color_t color, fill_t fillit)
01693 {
01694     foreground(color);
01695     return circle(x,y,radius,fillit);
01696 }
01697 
01698 
01699 RetCode_t RA8875::circle(loc_t x, loc_t y, dim_t radius, fill_t fillit)
01700 {
01701     RetCode_t ret = noerror;
01702 
01703     PERFORMANCE_RESET;
01704     if (radius <= 0 || (x - radius) < 0 || (x + radius) > screenwidth 
01705     || (y - radius) < 0 || (y + radius) > screenheight) {
01706         ret = bad_parameter;
01707     } else if (radius == 1) {
01708         pixel(x,y);
01709     } else {
01710         WriteCommandW(0x99, x);
01711         WriteCommandW(0x9B, y);
01712         WriteCommand(0x9d, radius & 0xFF);
01713         unsigned char drawCmd = 0x00;       // Circle
01714         if (fillit == FILL)
01715             drawCmd |= 0x20;
01716         WriteCommand(0x90, drawCmd);
01717         WriteCommand(0x90, 0x40 + drawCmd); // Start drawing.
01718         if (!_WaitWhileReg(0x90, 0x40)) {
01719             REGISTERPERFORMANCE(PRF_DRAWCIRCLE);
01720             return external_abort;
01721         }
01722     }
01723     REGISTERPERFORMANCE(PRF_DRAWCIRCLE);
01724     return ret;
01725 }
01726 
01727 
01728 RetCode_t RA8875::ellipse(loc_t x, loc_t y, dim_t radius1, dim_t radius2, color_t color, fill_t fillit)
01729 {
01730     foreground(color);
01731     return ellipse(x,y,radius1,radius2,fillit);
01732 }
01733 
01734 
01735 RetCode_t RA8875::fillellipse(loc_t x, loc_t y, dim_t radius1, dim_t radius2, color_t color, fill_t fillit)
01736 {
01737     foreground(color);
01738     return ellipse(x,y,radius1,radius2,fillit);
01739 }
01740 
01741 
01742 RetCode_t RA8875::ellipse(loc_t x, loc_t y, dim_t radius1, dim_t radius2, fill_t fillit)
01743 {
01744     RetCode_t ret = noerror;
01745 
01746     PERFORMANCE_RESET;
01747     if (radius1 <= 0 || radius2 <= 0 || (x - radius1) < 0 || (x + radius1) > screenwidth 
01748     || (y - radius2) < 0 || (y + radius2) > screenheight) {
01749         ret = bad_parameter;
01750     } else if (radius1 == 1 && radius2 == 1) {
01751         pixel(x, y);
01752     } else {
01753         WriteCommandW(0xA5, x);
01754         WriteCommandW(0xA7, y);
01755         WriteCommandW(0xA1, radius1);
01756         WriteCommandW(0xA3, radius2);
01757         unsigned char drawCmd = 0x00;   // Ellipse
01758         if (fillit == FILL)
01759             drawCmd |= 0x40;
01760         WriteCommand(0xA0, drawCmd);
01761         WriteCommand(0xA0, 0x80 + drawCmd); // Start drawing.
01762         if (!_WaitWhileReg(0xA0, 0x80)) {
01763             REGISTERPERFORMANCE(PRF_DRAWELLIPSE);
01764             return external_abort;
01765         }
01766     }
01767     REGISTERPERFORMANCE(PRF_DRAWELLIPSE);
01768     return ret;
01769 }
01770 
01771 
01772 RetCode_t RA8875::frequency(unsigned long Hz, unsigned long Hz2)
01773 {
01774     spiwritefreq = Hz;
01775     if (Hz2 != 0)
01776         spireadfreq = Hz2;
01777     else
01778         spireadfreq = Hz/2;
01779     _setWriteSpeed(true);
01780     //       __   ___
01781     // Clock   ___A     Rising edge latched
01782     //       ___ ____
01783     // Data  ___X____
01784     spi.format(8, 3);           // 8 bits and clock to data phase 0
01785     return noerror;
01786 }
01787 
01788 void RA8875::_setWriteSpeed(bool writeSpeed)
01789 {
01790     if (writeSpeed) {
01791         spi.frequency(spiwritefreq);
01792         spiWriteSpeed = true;
01793     } else {
01794         spi.frequency(spireadfreq);
01795         spiWriteSpeed = false;
01796     }
01797 }
01798 
01799 
01800 
01801 RetCode_t RA8875::BlockMove(uint8_t dstLayer, uint8_t dstDataSelect, point_t dstPoint,
01802     uint8_t srcLayer, uint8_t srcDataSelect, point_t srcPoint,
01803     dim_t bte_width, dim_t bte_height,
01804     uint8_t bte_op_code, uint8_t bte_rop_code)
01805 {
01806     uint8_t cmd;
01807 
01808     PERFORMANCE_RESET;
01809     ///@todo range check and error return rather than to secretly fix
01810     srcPoint.x &= 0x3FF;    // prevent high bits from doing unexpected things
01811     srcPoint.y &= 0x1FF;
01812     dstPoint.x &= 0x3FF;
01813     dstPoint.y &= 0x1FF;
01814     WriteCommandW(0x54, srcPoint.x);
01815     WriteCommandW(0x56, ((dim_t)(srcLayer & 1) << 15) | srcPoint.y);
01816     WriteCommandW(0x58, dstPoint.x);
01817     WriteCommandW(0x5A, ((dim_t)(dstLayer & 1) << 15) | dstPoint.y);
01818     WriteCommandW(0x5C, bte_width);
01819     WriteCommandW(0x5E, bte_height);
01820     WriteCommand(0x51,  ((bte_rop_code & 0x0F) << 4) | (bte_op_code & 0x0F));
01821     cmd = ((srcDataSelect & 1) << 6) | ((dstDataSelect & 1) << 5);
01822     WriteCommand(0x50, 0x80 | cmd);     // enable the BTE
01823     if (!_WaitWhileBusy(0x40)) {
01824         REGISTERPERFORMANCE(PRF_BLOCKMOVE);
01825         return external_abort;
01826     }
01827     REGISTERPERFORMANCE(PRF_BLOCKMOVE);
01828     return noerror;
01829 }
01830 
01831 
01832 RetCode_t RA8875::Power(bool on)
01833 {
01834     WriteCommand(0x01, (on) ? 0x80 : 0x00);
01835     return noerror;
01836 }
01837 
01838 
01839 RetCode_t RA8875::Backlight_u8(uint8_t brightness)
01840 {
01841     static bool is_enabled = false;
01842     
01843     if (brightness == 0) {
01844         WriteCommand(0x8a); // Disable the PWM
01845         WriteData(0x00);
01846         is_enabled = false;
01847     } else if (!is_enabled) {
01848         WriteCommand(0x8a); // Enable the PWM
01849         WriteData(0x80);
01850         WriteCommand(0x8a); // Not sure why this is needed, but following the pattern
01851         WriteData(0x81);    // open PWM (SYS_CLK / 2 as best I can tell)
01852         is_enabled = true;
01853     }
01854     WriteCommand(0x8b, brightness);  // Brightness parameter 0xff-0x00
01855     return noerror;
01856 }
01857 
01858 uint8_t RA8875::GetBacklight_u8(void)
01859 {
01860     return ReadCommand(0x8b);
01861 }
01862 
01863 RetCode_t RA8875::Backlight(float brightness)
01864 {
01865     unsigned char b;
01866 
01867     if (brightness >= 1.0)
01868         b = 255;
01869     else if (brightness <= 0.0)
01870         b = 0;
01871     else
01872         b = (unsigned char)(brightness * 255);
01873     return Backlight_u8(b);
01874 }
01875 
01876 float RA8875::GetBacklight(void)
01877 {
01878     return (float)(GetBacklight_u8())/255;
01879 }
01880 
01881 RetCode_t RA8875::SelectUserFont(const uint8_t * _font)
01882 {
01883     INFO("Cursor(%d,%d)  %p", cursor_x, cursor_y, _font);
01884     INFO("Text C(%d,%d)", GetTextCursor_X(), GetTextCursor_Y());
01885     if (_font) {
01886         HexDump("Font Memory", _font, 16);
01887         extFontHeight = _font[6];
01888         uint32_t totalWidth = 0;
01889         uint16_t firstChar = _font[3] * 256 + _font[2];
01890         uint16_t lastChar  = _font[5] * 256 + _font[4];
01891         uint16_t i;
01892         
01893         for (i=firstChar; i<=lastChar; i++) {
01894             // 8 bytes of preamble to the first level lookup table
01895             uint16_t offsetToCharLookup = 8 + 4 * (i - firstChar);    // 4-bytes: width(pixels), 16-bit offset from table start, 0
01896             totalWidth += _font[offsetToCharLookup];
01897         }
01898         extFontWidth = totalWidth / (lastChar - firstChar);
01899         INFO("Font Metrics: Avg W: %2d, H: %2d, First:%d, Last:%d", extFontWidth, extFontHeight, firstChar, lastChar);
01900     }
01901     SetTextCursor(GetTextCursor_X(), GetTextCursor_Y());  // soft-font cursor -> hw cursor
01902     font = _font;
01903     return GraphicsDisplay::SelectUserFont(_font);
01904 }
01905 
01906 RetCode_t RA8875::background(color_t color)
01907 {
01908     GraphicsDisplay::background(color);
01909     return _writeColorTrio(0x60, color);
01910 }
01911 
01912 
01913 RetCode_t RA8875::background(unsigned char r, unsigned char g, unsigned char b)
01914 {
01915     background(RGB(r,g,b));
01916     return noerror;
01917 }
01918 
01919 
01920 RetCode_t RA8875::foreground(color_t color)
01921 {
01922     GraphicsDisplay::foreground(color);
01923     return _writeColorTrio(0x63, color);
01924 }
01925 
01926 
01927 RetCode_t RA8875::foreground(unsigned char r, unsigned char g, unsigned char b)
01928 {
01929     foreground(RGB(r,g,b));
01930     return noerror;
01931 }
01932 
01933 
01934 color_t RA8875::GetForeColor(void)
01935 {
01936     return _readColorTrio(0x63);
01937 }
01938 
01939 
01940 color_t RA8875::DOSColor(int i)
01941 {
01942     const color_t colors[16] = {
01943         Black,    Blue,       Green,       Cyan,
01944         Red,      Magenta,    Brown,       Gray,
01945         Charcoal, BrightBlue, BrightGreen, BrightCyan,
01946         Orange,   Pink,       Yellow,      White
01947     };
01948     if (i >= 0 && i < 16)
01949         return colors[i];
01950     else
01951         return 0;
01952 }
01953 
01954 
01955 const char * RA8875::DOSColorNames(int i)
01956 {
01957     const char * names[16] = {
01958         "Black",    "Blue",       "Green",       "Cyan",
01959         "Red",      "Magenta",    "Brown",       "Gray",
01960         "Charcoal", "BrightBlue", "BrightGreen", "BrightCyan",
01961         "Orange",   "Pink",       "Yellow",      "White"
01962     };
01963     if (i >= 0 && i < 16)
01964         return names[i];
01965     else
01966         return NULL;
01967 }
01968 
01969 
01970 ///////////////////////////////////////////////////////////////
01971 // Private functions
01972 
01973 unsigned char RA8875::_spiwrite(unsigned char data)
01974 {
01975     unsigned char retval;
01976 
01977     if (!spiWriteSpeed)
01978         _setWriteSpeed(true);
01979     retval = spi.write(data);
01980     return retval;
01981 }
01982 
01983 
01984 unsigned char RA8875::_spiread(void)
01985 {
01986     unsigned char retval;
01987     unsigned char data = 0;
01988 
01989     if (spiWriteSpeed)
01990         _setWriteSpeed(false);
01991     retval = spi.write(data);
01992     return retval;
01993 }
01994 
01995 
01996 RetCode_t RA8875::_select(bool chipsel)
01997 {
01998     cs = (chipsel == true) ? 0 : 1;
01999     return noerror;
02000 }
02001 
02002 
02003 RetCode_t RA8875::PrintScreen(uint16_t layer, loc_t x, loc_t y, dim_t w, dim_t h, const char *Name_BMP)
02004 {
02005     (void)layer;
02006     
02007     // AttachPrintHandler(this, RA8875::_printCallback);
02008     // return PrintScreen(x,y,w,h);
02009     return PrintScreen(x, y, w, h, Name_BMP);
02010 }
02011 
02012 RetCode_t RA8875::_printCallback(RA8875::filecmd_t cmd, uint8_t * buffer, uint16_t size)
02013 {
02014     HexDump("CB", buffer, size);
02015     switch(cmd) {
02016         case RA8875::OPEN:
02017             //pc.printf("About to write %lu bytes\r\n", *(uint32_t *)buffer);
02018             _printFH = fopen("file.bmp", "w+b");
02019             if (_printFH == 0)
02020                 return file_not_found;
02021             break;
02022         case RA8875::WRITE:
02023             //pc.printf("  Write %4u bytes\r\n", size);
02024             fwrite(buffer, 1, size, _printFH);
02025             break;
02026         case RA8875::CLOSE:
02027             //pc.printf("  close\r\n");
02028             fclose(_printFH);
02029             _printFH = 0;
02030             break;
02031         default:
02032             //pc.printf("Unexpected callback %d\r\n", cmd);
02033             return file_not_found;
02034             //break;
02035     }
02036     return noerror;
02037 }
02038 
02039 RetCode_t RA8875::PrintScreen(loc_t x, loc_t y, dim_t w, dim_t h)
02040 {
02041     BITMAPFILEHEADER BMP_Header;
02042     BITMAPINFOHEADER BMP_Info;
02043     uint8_t * lineBuffer = NULL;
02044     color_t * pixelBuffer = NULL;
02045     color_t * pixelBuffer2 = NULL;
02046     
02047     INFO("(%d,%d) - (%d,%d)", x,y,w,h);
02048     if (x >= 0 && x < screenwidth
02049             && y >= 0 && y < screenheight
02050             && w > 0 && x + w <= screenwidth
02051             && h > 0 && y + h <= screenheight) {
02052 
02053         BMP_Header.bfType = BF_TYPE;
02054         BMP_Header.bfSize = (w * h * sizeof(RGBQUAD)) + sizeof(BMP_Header) + sizeof(BMP_Header);
02055         BMP_Header.bfReserved1 = 0;
02056         BMP_Header.bfReserved2 = 0;
02057         BMP_Header.bfOffBits = sizeof(BMP_Header) + sizeof(BMP_Header);
02058 
02059         BMP_Info.biSize = sizeof(BMP_Info);
02060         BMP_Info.biWidth = w;
02061         BMP_Info.biHeight = h;
02062         BMP_Info.biPlanes = 1;
02063         BMP_Info.biBitCount = 24;
02064         BMP_Info.biCompression = BI_RGB;
02065         BMP_Info.biSizeImage = 0;
02066         BMP_Info.biXPelsPerMeter = 0;
02067         BMP_Info.biYPelsPerMeter = 0;
02068         BMP_Info.biClrUsed = 0;
02069         BMP_Info.biClrImportant = 0;
02070 
02071         // Allocate the memory we need to proceed
02072         int lineBufSize = ((24 * w + 7)/8);
02073         lineBuffer = (uint8_t *)swMalloc(lineBufSize);
02074         if (lineBuffer == NULL) {
02075             ERR("Not enough RAM for PrintScreen lineBuffer");
02076             return(not_enough_ram);
02077         }
02078 
02079         #define DOUBLEBUF /* one larger buffer instead of two */
02080         
02081         #ifdef DOUBLEBUF
02082         // In the "#else", pixelBuffer2 malloc returns a value, 
02083         // but is actually causing a failure later. 
02084         // This test helps determine if it is truly out of memory,
02085         // or if malloc is broken.
02086         pixelBuffer = (color_t *)swMalloc(2 * w * sizeof(color_t));
02087         pixelBuffer2 = pixelBuffer + (w * sizeof(color_t));
02088         #else
02089         pixelBuffer = (color_t *)swMalloc(w * sizeof(color_t));
02090         pixelBuffer2 = (color_t *)swMalloc(w * sizeof(color_t));
02091         #endif
02092         if (pixelBuffer == NULL || pixelBuffer2 == NULL) {
02093             ERR("Not enough RAM for pixelBuffer");
02094             #ifndef DOUBLEBUF
02095             if (pixelBuffer2)
02096                 swFree(pixelBuffer2);
02097             #endif
02098             if (pixelBuffer)
02099                 swFree(pixelBuffer);
02100             swFree(lineBuffer);
02101             return(not_enough_ram);
02102         }
02103 
02104         // Get the file primed...
02105         privateCallback(OPEN, (uint8_t *)&BMP_Header.bfSize, 4);
02106 
02107         // Be optimistic - don't check for errors.
02108         HexDump("BMP_Header", (uint8_t *)&BMP_Header, sizeof(BMP_Header));        
02109         //fwrite(&BMP_Header, sizeof(char), sizeof(BMP_Header), Image);
02110         privateCallback(WRITE, (uint8_t *)&BMP_Header, sizeof(BMP_Header));
02111 
02112         HexDump("BMP_Info", (uint8_t *)&BMP_Info, sizeof(BMP_Info));
02113         //fwrite(&BMP_Info, sizeof(char), sizeof(BMP_Info), Image);
02114         privateCallback(WRITE, (uint8_t *)&BMP_Info, sizeof(BMP_Info));
02115 
02116         //color_t transparency = GetBackgroundTransparencyColor();
02117         LayerMode_T ltpr0 = GetLayerMode();
02118 
02119         uint16_t prevLayer = GetDrawingLayer();
02120         // If only one of the layers is visible, select that layer
02121         switch(ltpr0) {
02122             case ShowLayer0:
02123                 SelectDrawingLayer(0);
02124                 break;
02125             case ShowLayer1:
02126                 SelectDrawingLayer(1);
02127                 break;
02128             default:
02129                 break;
02130         }
02131 
02132         // Read the display from the last line toward the top
02133         // so we can write the file in one pass.
02134         for (int j = h - 1; j >= 0; j--) {
02135             if (ltpr0 >= 2)             // Need to combine the layers...
02136                 SelectDrawingLayer(0);  // so read layer 0 first
02137             // Read one line of pixels to a local buffer
02138             if (getPixelStream(pixelBuffer, w, x,y+j) != noerror) {
02139                 ERR("getPixelStream error, and no recovery handler...");
02140             }
02141             if (ltpr0 >= 2) {           // Need to combine the layers...
02142                 SelectDrawingLayer(1);  // so read layer 1 next
02143                 if (getPixelStream(pixelBuffer2, w, x,y+j) != noerror) {
02144                     ERR("getPixelStream error, and no recovery handler...");
02145                 }
02146             }
02147             INFO("1st Color: %04X", pixelBuffer[0]);
02148             HexDump("Raster", (uint8_t *)pixelBuffer, w);
02149             // Convert the local buffer to RGBQUAD format
02150             int lb = 0;
02151             for (int i=0; i<w; i++) {
02152                 RGBQUAD q0 = RGB16ToRGBQuad(pixelBuffer[x+i]);      // Scale to 24-bits
02153                 RGBQUAD q1 = RGB16ToRGBQuad(pixelBuffer2[x+i]);     // Scale to 24-bits
02154                 switch (ltpr0) {
02155                     case 0:
02156                     case 1:
02157                     case 2: // lighten-overlay  (@TODO Not supported yet)
02158                     case 6: // Floating Windows     (@TODO not sure how to support)
02159                     default: // Reserved...
02160                         lineBuffer[lb++] = q0.rgbBlue;
02161                         lineBuffer[lb++] = q0.rgbGreen;
02162                         lineBuffer[lb++] = q0.rgbRed;
02163                         break;
02164                     case 3: // transparent mode (@TODO Read the background color register for transparent)
02165                     case 4: // boolean or
02166                         lineBuffer[lb++] = q0.rgbBlue | q1.rgbBlue;
02167                         lineBuffer[lb++] = q0.rgbGreen | q1.rgbGreen;
02168                         lineBuffer[lb++] = q0.rgbRed | q1.rgbRed;
02169                         break;
02170                     case 5: // boolean AND
02171                         lineBuffer[lb++] = q0.rgbBlue & q1.rgbBlue;
02172                         lineBuffer[lb++] = q0.rgbGreen & q1.rgbGreen;
02173                         lineBuffer[lb++] = q0.rgbRed & q1.rgbRed;
02174                         break;
02175                 }
02176             }
02177             if (j == h - 1) {
02178                 HexDump("Line", lineBuffer, lineBufSize);
02179             }
02180             // Write to disk
02181             //fwrite(lineBuffer, sizeof(char), lb, Image);
02182             privateCallback(WRITE, (uint8_t *)lineBuffer, lb);
02183         }
02184         SelectDrawingLayer(prevLayer);
02185         //fclose(Image);
02186         privateCallback(CLOSE, NULL, 0);
02187         
02188         #ifndef DOUBLEBUF
02189         if (pixelBuffer2)
02190             swFree(pixelBuffer2);
02191         #endif
02192         if (pixelBuffer)
02193             swFree(pixelBuffer);
02194         swFree(lineBuffer);
02195         INFO("Image closed");
02196         return noerror;
02197     } else {
02198         return bad_parameter;
02199     }
02200 }
02201 
02202 RetCode_t RA8875::PrintScreen(loc_t x, loc_t y, dim_t w, dim_t h, const char *Name_BMP)
02203 {
02204     BITMAPFILEHEADER BMP_Header;
02205     BITMAPINFOHEADER BMP_Info;
02206     uint8_t * lineBuffer = NULL;
02207     color_t * pixelBuffer = NULL;
02208     color_t * pixelBuffer2 = NULL;
02209     
02210     INFO("(%d,%d) - (%d,%d) %s", x,y,w,h,Name_BMP);
02211     if (x >= 0 && x < screenwidth
02212             && y >= 0 && y < screenheight
02213             && w > 0 && x + w <= screenwidth
02214             && h > 0 && y + h <= screenheight) {
02215 
02216         BMP_Header.bfType = BF_TYPE;
02217         BMP_Header.bfSize = (w * h * sizeof(RGBQUAD)) + sizeof(BMP_Header) + sizeof(BMP_Header);
02218         BMP_Header.bfReserved1 = 0;
02219         BMP_Header.bfReserved2 = 0;
02220         BMP_Header.bfOffBits = sizeof(BMP_Header) + sizeof(BMP_Header);
02221 
02222         BMP_Info.biSize = sizeof(BMP_Info);
02223         BMP_Info.biWidth = w;
02224         BMP_Info.biHeight = h;
02225         BMP_Info.biPlanes = 1;
02226         BMP_Info.biBitCount = 24;
02227         BMP_Info.biCompression = BI_RGB;
02228         BMP_Info.biSizeImage = 0;
02229         BMP_Info.biXPelsPerMeter = 0;
02230         BMP_Info.biYPelsPerMeter = 0;
02231         BMP_Info.biClrUsed = 0;
02232         BMP_Info.biClrImportant = 0;
02233 
02234         // Allocate the memory we need to proceed
02235         int lineBufSize = ((24 * w + 7)/8);
02236         lineBuffer = (uint8_t *)swMalloc(lineBufSize);
02237         if (lineBuffer == NULL) {
02238             ERR("Not enough RAM for PrintScreen lineBuffer");
02239             return(not_enough_ram);
02240         }
02241 
02242         #define DOUBLEBUF /* one larger buffer instead of two */
02243         
02244         #ifdef DOUBLEBUF
02245         // In the "#else", pixelBuffer2 malloc returns a value, 
02246         // but is actually causing a failure later. 
02247         // This test helps determine if it is truly out of memory,
02248         // or if malloc is broken.
02249         pixelBuffer = (color_t *)swMalloc(2 * w * sizeof(color_t));
02250         pixelBuffer2 = pixelBuffer + (w * sizeof(color_t));
02251         #else
02252         pixelBuffer = (color_t *)swMalloc(w * sizeof(color_t));
02253         pixelBuffer2 = (color_t *)swMalloc(w * sizeof(color_t));
02254         #endif
02255         if (pixelBuffer == NULL || pixelBuffer2 == NULL) {
02256             ERR("Not enough RAM for pixelBuffer");
02257             #ifndef DOUBLEBUF
02258             if (pixelBuffer2)
02259                 swFree(pixelBuffer2);
02260             #endif
02261             if (pixelBuffer)
02262                 swFree(pixelBuffer);
02263             swFree(lineBuffer);
02264             return(not_enough_ram);
02265         }
02266 
02267         FILE *Image = fopen(Name_BMP, "wb");
02268         if (!Image) {
02269             ERR("Can't open file for write");
02270             #ifndef DOUBLEBUF
02271             if (pixelBuffer2)
02272                 swFree(pixelBuffer2);
02273             #endif
02274             if (pixelBuffer)
02275                 swFree(pixelBuffer);
02276             swFree(lineBuffer);
02277             return(file_not_found);
02278         }
02279 
02280         // Be optimistic - don't check for errors.
02281         HexDump("BMP_Header", (uint8_t *)&BMP_Header, sizeof(BMP_Header));
02282         fwrite(&BMP_Header, sizeof(char), sizeof(BMP_Header), Image);
02283 
02284         HexDump("BMP_Info", (uint8_t *)&BMP_Info, sizeof(BMP_Info));
02285         fwrite(&BMP_Info, sizeof(char), sizeof(BMP_Info), Image);
02286 
02287         //color_t transparency = GetBackgroundTransparencyColor();
02288         LayerMode_T ltpr0 = GetLayerMode();
02289 
02290         uint16_t prevLayer = GetDrawingLayer();
02291         // If only one of the layers is visible, select that layer
02292         switch(ltpr0) {
02293             case ShowLayer0:
02294                 SelectDrawingLayer(0);
02295                 break;
02296             case ShowLayer1:
02297                 SelectDrawingLayer(1);
02298                 break;
02299             default:
02300                 break;
02301         }
02302 
02303         // Read the display from the last line toward the top
02304         // so we can write the file in one pass.
02305         for (int j = h - 1; j >= 0; j--) {
02306             if (ltpr0 >= 2)             // Need to combine the layers...
02307                 SelectDrawingLayer(0);  // so read layer 0 first
02308             // Read one line of pixels to a local buffer
02309             if (getPixelStream(pixelBuffer, w, x,y+j) != noerror) {
02310                 ERR("getPixelStream error, and no recovery handler...");
02311             }
02312             if (ltpr0 >= 2) {           // Need to combine the layers...
02313                 SelectDrawingLayer(1);  // so read layer 1 next
02314                 if (getPixelStream(pixelBuffer2, w, x,y+j) != noerror) {
02315                     ERR("getPixelStream error, and no recovery handler...");
02316                 }
02317             }
02318             INFO("1st Color: %04X", pixelBuffer[0]);
02319             HexDump("Raster", (uint8_t *)pixelBuffer, w);
02320             // Convert the local buffer to RGBQUAD format
02321             int lb = 0;
02322             for (int i=0; i<w; i++) {
02323                 RGBQUAD q0 = RGB16ToRGBQuad(pixelBuffer[x+i]);      // Scale to 24-bits
02324                 RGBQUAD q1 = RGB16ToRGBQuad(pixelBuffer2[x+i]);     // Scale to 24-bits
02325                 switch (ltpr0) {
02326                     case 0:
02327                     case 1:
02328                     case 2: // lighten-overlay  (@TODO Not supported yet)
02329                     case 6: // Floating Windows     (@TODO not sure how to support)
02330                     default: // Reserved...
02331                         lineBuffer[lb++] = q0.rgbBlue;
02332                         lineBuffer[lb++] = q0.rgbGreen;
02333                         lineBuffer[lb++] = q0.rgbRed;
02334                         break;
02335                     case 3: // transparent mode (@TODO Read the background color register for transparent)
02336                     case 4: // boolean or
02337                         lineBuffer[lb++] = q0.rgbBlue | q1.rgbBlue;
02338                         lineBuffer[lb++] = q0.rgbGreen | q1.rgbGreen;
02339                         lineBuffer[lb++] = q0.rgbRed | q1.rgbRed;
02340                         break;
02341                     case 5: // boolean AND
02342                         lineBuffer[lb++] = q0.rgbBlue & q1.rgbBlue;
02343                         lineBuffer[lb++] = q0.rgbGreen & q1.rgbGreen;
02344                         lineBuffer[lb++] = q0.rgbRed & q1.rgbRed;
02345                         break;
02346                 }
02347             }
02348             if (j == h - 1) {
02349                 HexDump("Line", lineBuffer, lineBufSize);
02350             }
02351             // Write to disk
02352             fwrite(lineBuffer, sizeof(char), lb, Image);
02353         }
02354         SelectDrawingLayer(prevLayer);
02355         fclose(Image);
02356         #ifndef DOUBLEBUF
02357         if (pixelBuffer2)
02358             swFree(pixelBuffer2);
02359         #endif
02360         if (pixelBuffer)
02361             swFree(pixelBuffer);
02362         swFree(lineBuffer);
02363         INFO("Image closed");
02364         return noerror;
02365     } else {
02366         return bad_parameter;
02367     }
02368 }
02369 
02370 
02371 // ##########################################################################
02372 // ##########################################################################
02373 // ##########################################################################
02374 
02375 #ifdef TESTENABLE
02376 
02377 #include "BPG_Arial08x08.h"
02378 #include "BPG_Arial20x20.h"
02379 
02380 //      ______________  ______________  ______________  _______________
02381 //     /_____   _____/ /  ___________/ /  ___________/ /_____   ______/
02382 //          /  /      /  /            /  /                  /  /
02383 //         /  /      /  /___         /  /__________        /  /
02384 //        /  /      /  ____/        /__________   /       /  /
02385 //       /  /      /  /                       /  /       /  /
02386 //      /  /      /  /__________  ___________/  /       /  /
02387 //     /__/      /_____________/ /_____________/       /__/
02388 //
02389 //    Everything from here down is test code.
02390 //
02391 bool SuppressSlowStuff = false;
02392 
02393 void TextWrapTest(RA8875 & display, Serial & pc)
02394 {
02395     if (!SuppressSlowStuff)
02396         pc.printf("Text Wrap Test\r\n");
02397     display.background(Black);
02398     display.foreground(Blue);
02399     display.cls();
02400     display.Backlight_u8(255);
02401     display.puts("Text Wrap Test.\r\n");
02402     for (int i=1; i<60; i++) {
02403         display.printf("L%2d\n", i % 17);
02404         if (!SuppressSlowStuff)
02405             wait_ms(100);
02406     }
02407     if (!SuppressSlowStuff)
02408         wait_ms(3000);
02409 }
02410 
02411 
02412 void ShowKey(RA8875 & display, int key)
02413 {
02414     loc_t col, row;
02415     dim_t r1 = 25;
02416     color_t color = (key & 0x80) ? Red : Green;
02417 
02418     key &= 0x7F;        // remove the long-press flag
02419     row = (key - 1) / 5;
02420     col = (key - 1) % 5;
02421     if (col > 5) col = 5;
02422     if (row > 4) row = 4;
02423     display.circle(450 - + (2 * r1) * col, 200 - (2 * r1) * row, r1-2, color, FILL);
02424 }
02425 
02426 void HideKey(RA8875 & display, int key)
02427 {
02428     loc_t col, row;
02429     dim_t r1 = 25;
02430 
02431     row = (key - 1) / 5;
02432     col = (key - 1) % 5;
02433     if (col > 5) col = 5;
02434     if (row > 4) row = 4;
02435     display.background(Black);
02436     display.circle(450 - (2 * r1) * col, 200 - (2 * r1) * row, r1-2, Black, FILL);
02437     display.circle(450 - (2 * r1) * col, 200 - (2 * r1) * row, r1-2, Blue);
02438 }
02439 
02440 void KeyPadTest(RA8875 & display, Serial & pc)
02441 {
02442     const uint8_t myMap[22] = {
02443         0,
02444         'a', 'b', 'c', 'd', 'e',
02445         'f', 'g', 'h', 'i', 'j',
02446         'k', 'l', 'm', 'n', 'o',
02447         'p', 'q', 'r', 's', 't',
02448         'x'
02449     };
02450 
02451     display.background(Black);
02452     display.foreground(Blue);
02453     display.cls();
02454     display.Backlight_u8(255);
02455     display.puts("KeyPad Test. Touch the keypad...");
02456     pc.printf("\r\n"
02457               "Raw KeyPad Test. Keypad returns the key-number.\r\n"
02458               "Press [most] any PC keyboard key to advance to next test.\r\n");
02459     RetCode_t ret = display.KeypadInit(true, true, 3, 7, 3);
02460     if (ret != noerror)
02461         pc.printf("returncode from KeypadInit is %d\r\n", ret);
02462     int lastKey = 0;
02463     while (!pc.readable()) {
02464         if (display.readable()) {
02465             int key = display.getc();
02466             if (key) {
02467                 if (((key & 0x7F) != lastKey) && (lastKey != 0))
02468                     HideKey(display, lastKey);
02469                 ShowKey(display, key);
02470                 lastKey = key & 0x7F;
02471             } else {
02472                 // erase the last one
02473                 if (lastKey)
02474                     HideKey(display, lastKey);
02475             }
02476         }
02477     }
02478     (void)pc.getc();
02479     pc.printf("\r\n"
02480               "Map KeyPad Test. Keypad returns the remapped key 'a' - 't'.\r\n"
02481               "Press [most] any PC keyboard key to advance to exit test.\r\n");
02482     display.SetKeyMap(myMap);
02483     while (!pc.readable()) {
02484         if (display.readable()) {
02485             int key = display.getc();
02486             bool longPress = key & 0x80;
02487             display.SetTextCursor(0, 120);
02488             display.printf("Long Press: %d\r\n", longPress);
02489             display.printf("  Remapped: %c %02X\r\n", (key) ? key & 0x7F : ' ', key);
02490         }
02491     }
02492     (void)pc.getc();
02493     display.SetKeyMap();
02494     pc.printf("\r\n");
02495 }
02496 
02497 void TextCursorTest(RA8875 & display, Serial & pc)
02498 {
02499     const char * iCursor  = "The I-Beam cursor should be visible for this text.\r\n";
02500     const char * uCursor  = "The Underscore cursor should be visible for this text.\r\n";
02501     const char * bCursor  = "The Block cursor should be visible for this text.\r\n";
02502     const char * bbCursor = "The Blinking Block cursor should be visible for this text.\r\n";
02503     const char * p;
02504     int delay = 60;
02505 
02506     if (!SuppressSlowStuff)
02507         pc.printf("Text Cursor Test\r\n");
02508     else
02509         delay = 0;
02510     display.background(Black);
02511     display.foreground(Blue);
02512     display.cls();
02513     display.Backlight_u8(255);
02514     display.puts("Text Cursor Test.");
02515 
02516     // visible, non-blinking
02517     display.SetTextCursor(0,20);
02518     display.SetTextCursorControl(RA8875::IBEAM, false);
02519     p = iCursor;
02520     while (*p) {
02521         display._putc(*p++);
02522         wait_ms(delay);
02523     }
02524 
02525     display.SetTextCursorControl(RA8875::UNDER, false);
02526     p = uCursor;
02527     while (*p) {
02528         display._putc(*p++);
02529         wait_ms(delay);
02530     }
02531 
02532     display.SetTextCursorControl(RA8875::BLOCK, false);
02533     p = bCursor;
02534     while (*p) {
02535         display._putc(*p++);
02536         wait_ms(delay);
02537     }
02538 
02539     display.SetTextCursorControl(RA8875::BLOCK, true);
02540     p = bbCursor;
02541     while (*p) {
02542         display._putc(*p++);
02543         wait_ms(delay);
02544     }
02545     wait_ms(delay * 20);
02546     display.SetTextCursorControl(RA8875::NOCURSOR, false);
02547 }
02548 
02549 
02550 void BacklightTest(RA8875 & display, Serial & pc, float ramptime)
02551 {
02552     char buf[60];
02553     unsigned int w = (ramptime * 1000)/ 256;
02554     int delay = 200;
02555 
02556     if (!SuppressSlowStuff)
02557         pc.printf("Backlight Test - ramp over %f sec.\r\n", ramptime);
02558     else {
02559         delay = 0;
02560         w = 0;
02561     }
02562     display.Backlight_u8(0);
02563     display.background(White);
02564     display.foreground(Blue);
02565     display.cls();
02566     display.puts("RA8875 Backlight Test - Ramp up.");
02567     wait_ms(delay);
02568     for (int i=0; i <= 255; i++) {
02569         snprintf(buf, sizeof(buf), "%3d, %4d", i, w);
02570         display.puts(100,100,buf);
02571         display.Backlight_u8(i);
02572         wait_ms(w);
02573     }
02574 }
02575 
02576 
02577 void BacklightTest2(RA8875 & display, Serial & pc)
02578 {
02579     int delay = 20;
02580 
02581     if (!SuppressSlowStuff)
02582         pc.printf("Backlight Test 2\r\n");
02583     else
02584         delay = 0;
02585 
02586     // Dim it out at the end of the tests.
02587     display.foreground(Blue);
02588     display.puts(0,0, "Ramp Backlight down.");
02589     // Ramp it off
02590     for (int i=255; i != 0; i--) {
02591         display.Backlight_u8(i);
02592         wait_ms(delay);
02593     }
02594     display.Backlight_u8(0);
02595 }
02596 
02597 
02598 void ExternalFontTest(RA8875 & display, Serial & pc)
02599 {
02600     if (!SuppressSlowStuff)
02601         pc.printf("External Font Test\r\n");
02602     display.background(Black);
02603     display.foreground(Blue);
02604     display.cls();
02605     display.puts("External Font Test.");
02606     display.Backlight(1);
02607 
02608     display.SelectUserFont(BPG_Arial08x08);
02609     display.puts(0,30, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\r\n");
02610 
02611     display.SelectUserFont(BPG_Arial20x20);
02612     display.puts("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\r\n");
02613     
02614     display.SelectUserFont();
02615 
02616     display.puts("Normal font again.");
02617     //display.window(0,0, display.width(), display.height());
02618 }
02619 
02620 
02621 void DOSColorTest(RA8875 & display, Serial & pc)
02622 {
02623     if (!SuppressSlowStuff)
02624         pc.printf("DOS Color Test\r\n");
02625     display.background(Black);
02626     display.foreground(Blue);
02627     display.cls();
02628     display.puts("DOS Colors - Fore");
02629     display.puts(280,0, "Back");
02630     display.background(Gray);
02631     for (int i=0; i<16; i++) {
02632         display.foreground(display.DOSColor(i));
02633         display.puts(160, i*16, display.DOSColorNames(i));
02634         display.background(Black);
02635     }
02636     display.foreground(White);
02637     for (int i=0; i<16; i++) {
02638         display.background(display.DOSColor(i));
02639         display.puts(360, i*16, display.DOSColorNames(i));
02640         display.foreground(White);
02641     }
02642 }
02643 
02644 
02645 void WebColorTest(RA8875 & display, Serial & pc)
02646 {
02647     if (!SuppressSlowStuff)
02648         pc.printf("Web Color Test\r\n");
02649     display.background(Black);
02650     display.foreground(Blue);
02651     display.window(0,0, display.width(), display.height());
02652     display.cls();
02653     display.SetTextFontSize(1,1);
02654     display.puts(200,0, "Web Color Test");
02655     display.SetTextCursor(0,0);
02656     display.puts("  ");
02657     for (int i=0; i<16; i++)
02658         display.printf("%X", i&0xF);
02659     display.puts("\r\n0 ");
02660     for (int i=0; i<sizeof(WebColors)/sizeof(WebColors[0]); i++) {
02661         display.background(WebColors[i]);
02662         display.puts(" ");
02663         if (i % 16 == 15 && i < 255) {
02664             display.printf("\r\n%X ", ((i+1)/16));
02665         }
02666     }
02667     display.SetTextFontSize(1,1);
02668 }
02669 
02670 
02671 void PixelTest(RA8875 & display, Serial & pc)
02672 {
02673     int i, c, x, y;
02674 
02675     if (!SuppressSlowStuff)
02676         pc.printf("Pixel Test\r\n");
02677     display.background(Black);
02678     display.foreground(Blue);
02679     display.cls();
02680     display.puts("Pixel Test");
02681     for (i=0; i<1000; i++) {
02682         x = rand() % 480;
02683         y = 16 + rand() % (272-16);
02684         c = rand() % 16;
02685         //pc.printf("  (%d,%d) - %d\r\n", x,y,r1);
02686         display.pixel(x,y, display.DOSColor(c));
02687     }
02688 }
02689 
02690 
02691 void LineTest(RA8875 & display, Serial & pc)
02692 {
02693     int i, x, y, x2, y2;
02694 
02695     if (!SuppressSlowStuff)
02696         pc.printf("Line Test\r\n");
02697     display.background(Black);
02698     display.foreground(Blue);
02699     display.cls();
02700     display.puts("Line Test");
02701     for (i=0; i<16; i++) {
02702         // Lines
02703         x = rand() % 480;
02704         y = rand() % 272;
02705         x2 = rand() % 480;
02706         y2 = rand() % 272;
02707         display.line(x,y, x2,y2, display.DOSColor(i));
02708     }
02709     display.foreground(BrightRed);
02710     display.foreground(BrightGreen);
02711     display.foreground(BrightBlue);
02712     display.line(55,50, 79,74, BrightRed);
02713     display.line(57,50, 81,74, BrightGreen);
02714     display.line(59,50, 83,74, BrightBlue);
02715     // horz
02716     display.line(30,40, 32,40, BrightRed);
02717     display.line(30,42, 32,42, BrightGreen);
02718     display.line(30,44, 32,44, BrightBlue);
02719     // vert
02720     display.line(20,40, 20,42, BrightRed);
02721     display.line(22,40, 22,42, BrightGreen);
02722     display.line(24,40, 24,42, BrightBlue);
02723     // compare point to line-point
02724     display.pixel(20,50, BrightRed);
02725     display.pixel(22,50, BrightGreen);
02726     display.pixel(24,50, BrightBlue);
02727     display.line(20,52, 20,52, BrightRed);
02728     display.line(22,52, 22,52, BrightGreen);
02729     display.line(24,52, 24,52, BrightBlue);
02730 
02731     // point
02732     display.line(50,50, 50,50, Red);
02733     display.line(52,52, 52,52, Green);
02734     display.line(54,54, 54,54, Blue);
02735     display.line(60,60, 60,60, BrightRed);
02736     display.line(62,62, 62,62, BrightGreen);
02737     display.line(64,64, 64,64, BrightBlue);
02738     display.line(70,70, 70,70, DarkRed);
02739     display.line(72,72, 72,72, DarkGreen);
02740     display.line(74,74, 74,74, DarkBlue);
02741 }
02742 
02743 
02744 void RectangleTest(RA8875 & display, Serial & pc)
02745 {
02746     int i, x1,y1, x2,y2;
02747 
02748     if (!SuppressSlowStuff)
02749         pc.printf("Rectangle Test\r\n");
02750     display.background(Black);
02751     display.foreground(Blue);
02752     display.cls();
02753     display.puts("Rectangle Test");
02754     for (i=0; i<16; i++) {
02755         x1 = rand() % 240;
02756         y1 = 50 + rand() % 200;
02757         x2 = rand() % 240;
02758         y2 = 50 + rand() % 200;
02759         display.rect(x1,y1, x2,y2, display.DOSColor(i));
02760 
02761         x1 = 240 + rand() % 240;
02762         y1 = 50 + rand() % 200;
02763         x2 = 240 + rand() % 240;
02764         y2 = 50 + rand() % 200;
02765         display.rect(x1,y1, x2,y2, FILL);
02766     }
02767 }
02768 
02769 
02770 void LayerTest(RA8875 & display, Serial & pc)
02771 {
02772     loc_t i, x1,y1, x2,y2, r1,r2;
02773 
02774     if (!SuppressSlowStuff)
02775         pc.printf("Layer Test\r\n");
02776 
02777     display.SelectDrawingLayer(0);
02778     display.background(Black);
02779     display.foreground(Blue);
02780     display.cls();
02781     display.puts("Layer 0");
02782     for (i=0; i<16; i++) {
02783         x1 = rand() % 240;
02784         y1 = 50 + rand() % 200;
02785         x2 = x1 + rand() % 100;
02786         y2 = y1 + rand() % 100;
02787         r1 = rand() % (x2 - x1)/2;
02788         r2 = rand() % (y2 - y1)/2;
02789         display.roundrect(x1,y1, x2,y2, r1,r2, display.DOSColor(i));
02790         if (!SuppressSlowStuff)
02791             wait_ms(20);
02792     }
02793     if (!SuppressSlowStuff)
02794         wait_ms(1000);
02795 
02796     display.SelectDrawingLayer(1);
02797     display.background(Black);
02798     display.foreground(Yellow);
02799     display.cls();
02800     display.puts(240,0, "Layer 1");
02801     for (i=0; i<16; i++) {
02802         x1 = 300 + rand() % 100;
02803         y1 = 70 + rand() % 200;
02804         r1 = rand() % min(y1 - 20, 100);
02805         display.circle(x1,y1,r1, display.DOSColor(i));
02806         if (!SuppressSlowStuff)
02807             wait_ms(20);
02808     }
02809     display.SetLayerMode(RA8875::ShowLayer1);        // Show it after the build-up
02810     if (!SuppressSlowStuff)
02811         wait_ms(2000);
02812 
02813     display.SelectDrawingLayer(0);
02814     display.SetLayerMode(RA8875::ShowLayer0);        // Show Layer 0 again
02815     if (!SuppressSlowStuff)
02816         wait_ms(1000);
02817     display.SetLayerMode(RA8875::TransparentMode);        // Transparent mode
02818     if (!SuppressSlowStuff)
02819         wait_ms(1000);
02820     for (i=0; i<=8; i++) {
02821         display.SetLayerTransparency(i, 8-i);
02822         if (!SuppressSlowStuff)
02823             wait_ms(200);
02824     }
02825 
02826     // Restore before we exit
02827     display.SetLayerTransparency(0, 0);
02828     display.SetLayerMode(RA8875::ShowLayer0);        // Restore to layer 0
02829 }
02830 
02831 
02832 void RoundRectTest(RA8875 & display, Serial & pc)
02833 {
02834     loc_t i, x1,y1, x2,y2, r1,r2;
02835 
02836     if (!SuppressSlowStuff)
02837         pc.printf("Round Rectangle Test\r\n");
02838     display.background(Black);
02839     display.foreground(Blue);
02840     display.cls();
02841     display.puts("Rounded Rectangle Test");
02842 
02843     for (i=0; i<16; i++) {
02844         x1 = rand() % 240;
02845         y1 = 50 + rand() % 200;
02846         x2 = x1 + rand() % 100;
02847         y2 = y1 + rand() % 100;
02848         r1 = rand() % (x2 - x1)/2;
02849         r2 = rand() % (y2 - y1)/2;
02850         display.roundrect(x1,y1, x2,y2, 5,8, display.DOSColor(i));
02851 
02852         x1 = 240 + rand() % 240;
02853         y1 = 50 + rand() % 200;
02854         x2 = x1 + rand() % 100;
02855         y2 = y1 + rand() % 100;
02856         r1 = rand() % (x2 - x1)/2;
02857         r2 = rand() % (y2 - y1)/2;
02858         display.roundrect(x1,y1, x2,y2, r1,r2, FILL);
02859     }
02860 }
02861 
02862 
02863 void TriangleTest(RA8875 & display, Serial & pc)
02864 {
02865     int i, x1, y1, x2, y2, x3, y3;
02866 
02867     if (!SuppressSlowStuff)
02868         pc.printf("Triangle Test\r\n");
02869     display.background(Black);
02870     display.foreground(Blue);
02871     display.cls();
02872     display.puts(0,0, "Triangle Test");
02873 
02874     x1 = 150;
02875     y1 = 2;
02876     x2 = 190;
02877     y2 = 7;
02878     x3 = 170;
02879     y3 = 16;
02880     display.triangle(x1,y1, x2,y2, x3,y3);
02881 
02882     x1 = 200;
02883     y1 = 2;
02884     x2 = 240;
02885     y2 = 7;
02886     x3 = 220;
02887     y3 = 16;
02888     display.filltriangle(x1,y1, x2,y2, x3,y3, BrightRed);
02889 
02890     x1 = 300;
02891     y1 = 2;
02892     x2 = 340;
02893     y2 = 7;
02894     x3 = 320;
02895     y3 = 16;
02896     display.triangle(x1,y1, x2,y2, x3,y3, NOFILL);
02897 
02898     x1 = 400;
02899     y1 = 2;
02900     x2 = 440;
02901     y2 = 7;
02902     x3 = 420;
02903     y3 = 16;
02904     display.triangle(x1,y1, x2,y2, x3,y3, Blue);
02905 
02906     for (i=0; i<16; i++) {
02907         x1 = rand() % 240;
02908         y1 = 50 + rand() % 200;
02909         x2 = rand() % 240;
02910         y2 = 50 + rand() % 200;
02911         x3 = rand() % 240;
02912         y3 = 50 + rand() % 200;
02913         display.triangle(x1,y1, x2,y2, x3,y3, display.DOSColor(i));
02914         x1 = 240 + rand() % 240;
02915         y1 = 50 + rand() % 200;
02916         x2 = 240 + rand() % 240;
02917         y2 = 50 + rand() % 200;
02918         x3 = 240 + rand() % 240;
02919         y3 = 50 + rand() % 200;
02920         display.triangle(x1,y1, x2,y2, x3,y3, FILL);
02921     }
02922 }
02923 
02924 
02925 void CircleTest(RA8875 & display, Serial & pc)
02926 {
02927     int i, x, y, r1;
02928 
02929     if (!SuppressSlowStuff)
02930         pc.printf("Circle Test\r\n");
02931     display.background(Black);
02932     display.foreground(Blue);
02933     display.cls();
02934     display.puts("Circle Test");
02935     for (i=0; i<16; i++) {
02936         x = 100 + rand() % 100;
02937         y = 70 + rand() % 200;
02938         r1 = rand() % min(y - 20, 100);
02939         //pc.printf("  (%d,%d) - %d\r\n", x,y,r1);
02940         display.circle(x,y,r1, display.DOSColor(i));
02941 
02942         x = 300 + rand() % 100;
02943         y = 70 + rand() % 200;
02944         r1 = rand() % min(y - 20, 100);
02945         //pc.printf("  (%d,%d) - %d FILL\r\n", x,y,r1);
02946         display.circle(x,y,r1, display.DOSColor(i), FILL);
02947     }
02948 }
02949 
02950 
02951 void EllipseTest(RA8875 & display, Serial & pc)
02952 {
02953     int i,x,y,r1,r2;
02954 
02955     if (!SuppressSlowStuff)
02956         pc.printf("Ellipse Test\r\n");
02957     display.background(Black);
02958     display.foreground(Blue);
02959     display.cls();
02960     display.puts("Ellipse Test");
02961     for (i=0; i<16; i++) {
02962         x = 100 + rand() % 100;
02963         y = 70 + rand() % 200;
02964         r1 = rand() % min(y - 20, 100);
02965         r2 = rand() % min(y - 20, 100);
02966         display.ellipse(x,y,r1,r2, display.DOSColor(i));
02967 
02968         x = 300 + rand() % 100;
02969         y = 70 + rand() % 200;
02970         r1 = rand() % min(y - 20, 100);
02971         r2 = rand() % min(y - 20, 100);
02972         display.ellipse(x,y,r1,r2, FILL);
02973     }
02974 }
02975 
02976 
02977 void TestGraphicsBitmap(RA8875 & display, Serial & pc)
02978 {
02979     LocalFileSystem local("local");
02980     if (!SuppressSlowStuff)
02981         pc.printf("Bitmap File Load\r\n");
02982     display.background(Black);
02983     display.foreground(Blue);
02984     display.cls();
02985     display.puts("Graphics Test, loading /local/TestPat.bmp");
02986     wait(3);
02987 
02988     int r = display.RenderBitmapFile(0,0, "/local/TestPat.bmp");
02989     if (!SuppressSlowStuff)
02990         pc.printf("  returned %d\r\n", r);
02991 }
02992 
02993 
02994 void TouchPanelTest(RA8875 & display, Serial & pc)
02995 {
02996     Timer t;
02997     int x, y;
02998     tpMatrix_t calmatrix;
02999     
03000     display.background(Black);
03001     display.foreground(Blue);
03002     display.cls();
03003     display.puts("Touch Panel Test\r\n");
03004     pc.printf("Touch Panel Test\r\n");
03005     display.TouchPanelInit();
03006     pc.printf("  TP: c - calibrate, r - restore, t - test\r\n");
03007     int c = pc.getc();
03008     if (c == 'c') {
03009         point_t pTest[3] =
03010         { { 50, 50 }, {450, 150}, {225,250} };
03011         point_t pSample[3];
03012         for (int i=0; i<3; i++) {
03013             display.foreground(Blue);
03014             display.printf(" (%3d,%3d) => ", pTest[i].x, pTest[i].y);
03015             display.line(pTest[i].x-10, pTest[i].y, pTest[i].x+10, pTest[i].y, White);
03016             display.line(pTest[i].x, pTest[i].y-10, pTest[i].x, pTest[i].y+10, White);
03017             while (!display.TouchPanelA2DFiltered(&x, &y))
03018                 wait_ms(20);
03019             pSample[i].x = x;
03020             pSample[i].y = y;
03021             display.line(pTest[i].x-10, pTest[i].y, pTest[i].x+10, pTest[i].y, Black);
03022             display.line(pTest[i].x, pTest[i].y-10, pTest[i].x, pTest[i].y+10, Black);
03023             display.foreground(Blue);
03024             display.printf(" (%4d,%4d)\r\n", x,y);
03025             while (display.TouchPanelA2DFiltered(&x, &y))
03026                 wait_ms(20);
03027             wait(2);
03028         }
03029         display.TouchPanelComputeCalibration(pTest, pSample, &calmatrix);
03030         display.printf(" Writing calibration to tpcal.cfg\r\n");
03031         FILE * fh = fopen("/local/tpcal.cfg", "wb");
03032         if (fh) {
03033             fwrite(&calmatrix, sizeof(calmatrix), 1, fh);
03034             fclose(fh);
03035         }
03036         display.printf(" Calibration is complete.");
03037     } else if (c == 'r') {
03038         display.printf(" Reading calibration from tpcal.cfg\r\n");
03039         FILE * fh = fopen("/local/tpcal.cfg", "rb");
03040         if (fh) {
03041             fread(&calmatrix, sizeof(calmatrix), 1, fh);
03042             fclose(fh);
03043         }
03044         display.printf(" Calibration is complete.");
03045         display.TouchPanelSetMatrix(&calmatrix);
03046     }
03047     t.start();
03048     do {
03049         point_t point = {0, 0};
03050         if (display.TouchPanelReadable(&point)) {
03051             display.pixel(point.x, point.y, Red);
03052         }
03053     } while (t.read_ms() < 30000);
03054     pc.printf(">");
03055 }
03056 
03057 
03058 void SpeedTest(RA8875 & display, Serial & pc)
03059 {
03060     Timer t;
03061     SuppressSlowStuff = true;
03062     pc.printf("\r\nSpeedTest disables delays, runs tests, reports overall time.\r\n");
03063     t.start();
03064     // do stuff fast
03065     TextCursorTest(display, pc);
03066     TextWrapTest(display, pc);
03067     BacklightTest(display, pc, 0);
03068     BacklightTest2(display, pc);
03069     ExternalFontTest(display, pc);
03070     DOSColorTest(display, pc);
03071     WebColorTest(display, pc);
03072     PixelTest(display, pc);
03073     LineTest(display, pc);
03074     RectangleTest(display, pc);
03075     RoundRectTest(display, pc);
03076     TriangleTest(display, pc);
03077     CircleTest(display, pc);
03078     EllipseTest(display, pc);
03079     LayerTest(display, pc);
03080     //TestGraphicsBitmap(display, pc);
03081     pc.printf("SpeedTest completed in %d msec\r\n", t.read_ms());
03082 #ifdef PERF_METRICS
03083     display.ReportPerformance(pc);
03084 #endif
03085     SuppressSlowStuff = false;
03086 }
03087 
03088 
03089 void PrintScreen(RA8875 & display, Serial & pc)
03090 {
03091     if (!SuppressSlowStuff)
03092         pc.printf("PrintScreen\r\n");
03093     display.PrintScreen( 0,0, 480,272, "/local/Capture.bmp");
03094 }
03095 
03096 
03097 void RunTestSet(RA8875 & lcd, Serial & pc)
03098 {
03099     int q = 0;
03100     int automode = 0;
03101     const unsigned char modelist[] = "BDWtGLlFROTPCEbw";   // auto-test in this order.
03102 
03103     while(1) {
03104         pc.printf("\r\n"
03105                   "B - Backlight up      b - backlight dim\r\n"
03106                   "D - DOS Colors        W - Web Colors\r\n"
03107                   "t - text cursor       G - Graphics Bitmap\r\n"
03108                   "L - Lines             F - external Font\r\n"
03109                   "R - Rectangles        O - rOund rectangles\r\n"
03110                   "T - Triangles         P - Pixels  \r\n"
03111                   "C - Circles           E - Ellipses\r\n"
03112                   "A - Auto Test mode    S - Speed Test\r\n"
03113                   "K - Keypad Test       s - touch screen test\r\n"
03114                   "p - print screen      r - reset  \r\n"
03115                   "l - layer test        w - wrapping text \r\n"
03116 #ifdef PERF_METRICS
03117                   "0 - clear performance 1 - report performance\r\n"
03118 #endif
03119                   "> ");
03120         if (automode == -1 || pc.readable()) {
03121             automode = -1;
03122             q = pc.getc();
03123             while (pc.readable())
03124                 pc.getc();
03125         } else if (automode >= 0) {
03126             q = modelist[automode];
03127         }
03128         switch(q) {
03129 #ifdef PERF_METRICS
03130             case '0':
03131                 lcd.ClearPerformance();
03132                 break;
03133             case '1':
03134                 lcd.ReportPerformance(pc);
03135                 break;
03136 #endif
03137             case 'A':
03138                 automode = 0;
03139                 break;
03140             case 'B':
03141                 BacklightTest(lcd, pc, 2);
03142                 break;
03143             case 'b':
03144                 BacklightTest2(lcd, pc);
03145                 break;
03146             case 'D':
03147                 DOSColorTest(lcd, pc);
03148                 break;
03149             case 'K':
03150                 KeyPadTest(lcd, pc);
03151                 break;
03152             case 'W':
03153                 WebColorTest(lcd, pc);
03154                 break;
03155             case 't':
03156                 TextCursorTest(lcd, pc);
03157                 break;
03158             case 'w':
03159                 TextWrapTest(lcd, pc);
03160                 break;
03161             case 'F':
03162                 ExternalFontTest(lcd, pc);
03163                 break;
03164             case 'L':
03165                 LineTest(lcd, pc);
03166                 break;
03167             case 'l':
03168                 LayerTest(lcd, pc);
03169                 break;
03170             case 'R':
03171                 RectangleTest(lcd, pc);
03172                 break;
03173             case 'O':
03174                 RoundRectTest(lcd, pc);
03175                 break;
03176             case 'p':
03177                 PrintScreen(lcd, pc);
03178                 break;
03179             case 'S':
03180                 SpeedTest(lcd, pc);
03181                 break;
03182             case 's':
03183                 TouchPanelTest(lcd, pc);
03184                 break;
03185             case 'T':
03186                 TriangleTest(lcd, pc);
03187                 break;
03188             case 'P':
03189                 PixelTest(lcd, pc);
03190                 break;
03191             case 'G':
03192                 TestGraphicsBitmap(lcd, pc);
03193                 break;
03194             case 'C':
03195                 CircleTest(lcd, pc);
03196                 break;
03197             case 'E':
03198                 EllipseTest(lcd, pc);
03199                 break;
03200             case 'r':
03201                 pc.printf("Resetting ...\r\n");
03202                 wait_ms(20);
03203                 mbed_reset();
03204                 break;
03205             case ' ':
03206                 break;
03207             default:
03208                 printf("huh?\n");
03209                 break;
03210         }
03211         if (automode >= 0) {
03212             automode++;
03213             if (automode >= sizeof(modelist))
03214                 automode = 0;
03215             wait_ms(2000);
03216         }
03217         wait_ms(200);
03218     }
03219 }
03220 
03221 #endif // TESTENABLE