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