KSM edits to RA8875

Dependents:   Liz_Test_Code

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