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