LCD LIB

Dependents:   HagridOS5

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